要するに:リストで最小値を見つける方法は? (アドバイスカーレルに感謝します)
長い話:
Amziプロローグで加重グラフを作成し、2つのノードを指定すると、パスのリストを取得できます。ただし、このパスで最小値を見つける必要がありますが、これを行うためにリストをトラバースできません。リストの最小値を決定する方法についてアドバイスをお願いできますか?
私のコードは現在次のようになっています:
arc(1,2)。 arc(2,3)。 arc(3,4)。 arc(3,5)。 arc(3,6)。 arc(2,5)。 arc(5,6)。 arc(2,6)。 path(X、Z、A):- (arc(X、Y)、path(Y、Z、A1)、A is A1 + 1; arc(X、Z) 、Aは1です。
したがって、 'キーイングfindall(Z、path(2,6、Z)、L)。'リスナーでリスト[3,2,2,1]を取得できます。ここから最小値を取得し、金額を掛ける必要があります。誰かが最小値を取得する方法についてアドバイスできますか?ありがとう!
最初の引数のインデックス付けの恩恵を受けるために、いわゆる「ラグ引数」を使用するのが一般的です。
list_min([L|Ls], Min) :-
list_min(Ls, L, Min).
list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
Min1 is min(L, Min0),
list_min(Ls, Min1, Min).
このパターンはfold(左から)と呼ばれ、最近のSWIバージョンで使用可能なfoldl/4
を使用すると、次のように記述できます。
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min is min(X, Y).
ただし、これはすべての方向で使用できるわけではないことに注意してください。次に例を示します。
?- list_min([A,B], 5).
is/2: Arguments are not sufficiently instantiated
integersについて推論している場合は、例のように、したがって、CLP(FD)制約を使用して述語を自然に一般化することをお勧めします。 (is)/2
の代わりに、単に(#=)/2
を使用して、より宣言的なソリューションの恩恵を受けてください。
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min #= min(X, Y).
これは、すべての方向で機能する真の関係として使用できます。次に例を示します。
?- list_min([A,B], 5).
降伏:
A in 5..sup,
5#=min(B, A),
B in 5..sup.
これは私には正しく見えます( ここから )。
min_in_list([Min],Min). % We've found the minimum
min_in_list([H,K|T],M) :-
H =< K, % H is less than or equal to K
min_in_list([H|T],M). % so use H
min_in_list([H,K|T],M) :-
H > K, % H is greater than K
min_in_list([K|T],M). % so use K
%Usage: minl(List, Minimum).
minl([Only], Only).
minl([Head|Tail], Minimum) :-
minl(Tail, TailMin),
Minimum is min(Head, TailMin).
2番目のルールは再帰を実行します。英語では、「テールの最小値を取得し、Minimumをその値とヘッドの小さい方に設定します」。最初のルールは基本ケースであり、「1つのリストの最小値がリスト内の唯一の値です」。
テスト:
| ?- minl([2,4,1],1).
true ?
yes
| ?- minl([2,4,1],X).
X = 1 ?
yes
これを使用して、最初のケースで値をチェックするか、プロローグに2番目のケースで値を計算させることができます。
SWI-Prologはライブラリ(集合体)を提供します。一般化され、パフォーマンスが賢明です。
:- [library(aggregate)].
min(L, M) :- aggregate(min(E), member(E, L), M).
「is」のないソリューション。
min([],X,X).
min([H|T],M,X) :- H =< M, min(T,H,X).
min([H|T],M,X) :- M < H, min(T,M,X).
min([H|T],X) :- min(T,H,X).
これは私にとっては大丈夫です:
minimumList([X], X). %(The minimum is the only element in the list)
minimumList([X|Q], M) :- % We 'cut' our list to have one element, and the rest in Q
minimumList(Q, M1), % We call our predicate again with the smallest list Q, the minimum will be in M1
M is min(M1, X). % We check if our first element X is smaller than M1 as we unstack our calls
SWI-Prologにはmin_list/2
があります:
min_list(+List, -Min)
True if Min is the smallest number in List.
その定義はlibrary/lists.pl
にあります
min_list([H|T], Min) :-
min_list(T, H, Min).
min_list([], Min, Min).
min_list([H|T], Min0, Min) :-
Min1 is min(H, Min0),
min_list(T, Min1, Min).
min([Second_Last, Last], Result):-
Second_Last < Last
-> Result = Second_Last
; Result = Last, !.
min([First, Second|Rest], Result):-
First < Second
-> min([First|Rest], Result)
; min([Second|Rest], Result).
動作しているはずです。
このプログラムは遅いかもしれませんが、私はできる限り明らかに正しいコードを書くのが好きです。
最小(リスト、最小):-ソート(リスト、[最小| _])。
Andersojに似ていますが、二重比較の代わりにカットを使用します。
min([X], X).
min([X, Y | R], Min) :-
X < Y, !,
min([X | R], Min).
min([X, Y | R], Min) :-
min([Y | R], Min).
これは機能し、かなり効率的だと思われます。
min_in_list([M],M).
min_in_list([H|T],X) :-
min_in_list(T,M),
(H < M, X = H; X = M).
min_list(X,Y) :- min_in_list(X,Y), !.
返信ありがとうございます。役に立ちました。私はさらに実験し、この答えを開発しました:
% if list has only 1 element, it is the smallest. also, this is base case.
min_list([X],X).
min_list([H|List],X) :-
min_list(List,X1), (H =< X1,X is H; H > X1, X is X1).
% recursively call min_list with list and value,
% if H is less than X1, X1 is H, else it is the same.
これがアルゴリズム的にどれだけ良い答えであるかを判断する方法はまだわかりませんが、機能します!それでもフィードバックをいただければ幸いです。ありがとう!