2

整数LのリストでXの最小値とYの最大値を見つけるための述語minmax(L、X、Y)の記述方法。

例:

?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10, Y = 7.
4

4 に答える 4

3

list_minnum_maxnum/3のように定義しましょうlist_minnum/2:

list_minnum_maxnum([E|Es],Min,Max) :-
   V is E,
   list_minnum0_minnum_maxnum0_maxnum(Es,V,Min,V,Max).

list_minnum0_minnum_maxnum0_maxnum([]    ,Min ,Min,Max ,Max).
list_minnum0_minnum_maxnum0_maxnum([E|Es],Min0,Min,Max0,Max) :-
   V    is E,
   Min1 is min(Min0,V),
   Max1 is max(Max0,V),
   list_minnum0_minnum_maxnum0_maxnum(Es,Min1,Min,Max1,Max).

OPによって与えられたサンプルクエリ:

?- list_minnum_maxnum([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.

のこの実装はlist_minnum_maxnum/3、あらゆる種類の数値で機能することに注意してください。

?- list_minnum_maxnum([1,-10,1,0,7.2,7,7], Min,Max).
Min = -10,
Max = 7.2.

整数の処理のみに関心がある場合は、 を使用してください。

:- use_module(library(clpfd)).

次のように定義list_zmin_zmax/3します。

list_zmin_zmax([E|Es],Min,Max) :-
   V #= E,
   list_zmin0_zmin_zmax0_zmax(Es,V,Min,V,Max).

list_zmin0_zmin_zmax0_zmax([]    ,Min ,Min,Max ,Max).
list_zmin0_zmin_zmax0_zmax([E|Es],Min0,Min,Max0,Max) :-
   V    #= E,
   Min1 #= min(Min0,V),
   Max1 #= max(Max0,V),
   list_zmin0_zmin_zmax0_zmax(Es,Min1,Min,Max1,Max).

前と同じサンプルの使用:

?- list_zmin_zmax([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.

わかった!非整数のサポートについてはどうですか?

?- list_zmin_zmax([1,-10,1,0,7.2,7,7], Min,Max).
ERROR: Domain error: `clpfd_expression' expected, found `7.2'

エラーが発生することを期待していましたが、エラーが発生しました...

のおかげで、より一般的なクエリも実行できることに注意してください。

?- list_zmin_zmax([A,B], Min,Max).
A #>= Min, Max #>= A, Min #= min(A,B),
B #>= Min, Max #>= B, Max #= max(A,B).
于 2015-08-05T07:30:38.960 に答える
2

前述のように、リストを反復処理して、最小値と最大値を累積する必要があります。したがって、これをゼロから作成する必要があると仮定すると、最初に行う必要があるのは、問題を簡単な手順に分解することです。

  1. 2 つのオブジェクトを比較して、どちらが低いか高いかを判断する手段が必要です。
  2. ループを繰り返し処理し、最小値と最大値を追跡する手段が必要です。

min/3それはと につながるmax/3ので、次のようになります。

min(X,X,X).
min(X,Y,X) :- X < Y .
min(X,Y,Y) :- X > Y .

max(X,X,X).
max(X,Y,X) :- X > Y .
max(X,Y,Y) :- X < Y .

ここでの目的のために、必要に応じて、それらを 1 つの述語に結合することもできます。

rank( X , X , X , X ) .
rank( X , Y , X , Y ) :- X < Y .
rank( X , Y , Y , X ) :- X > Y .

Prolog での非常に典型的なプログラミングパターンは、実際の作業を行うプライベートな「ワーカー」述語を呼び出す単純なパブリック API 述語を持つことです。多くの場合、ワーカーの述語は、ジョブを単純化する一時的な「アキュムレータ」変数を保持します。パブリック述語は次のようになります。

minmax([X|Xs],Min,Max) :- minmax_scan( Xs , X , X , Min , Max ).

ここで、パブリック API 述語は空でないリストを受け入れ、ワーカー述語が使用する最小/最大アキュムレータをリストの先頭でシードし、リストの末尾でワーカー述語を呼び出します。

ワーカー述語は次のようになります。

% if the list is empty, we've solved the puzzle, right?
minmax_scan( [] , Min , Max , Min , Max ) .
% if the list is non-empty, we need to compare its head to
% the current value for min/max to determine the new values for min/max
% (which might be the same), and then recurse down on the tail of the list
minmax_scan( [X|Xs] , CurrMin , CurrMax , Min , Max ) :-
  min( X , CurrMin , NextMin ) ,
  max( X , CurrMax , NextMax ) ,
  minmax_scan( Xs , NextMin , NextMax , Min , Max )
  .

簡単!

于 2012-10-03T17:12:49.373 に答える
1

これは複雑で少し複雑です。

is_minmax(A,B-D,C-E) :-
    D is min(...),
    E is max(...) .

pair(A,B,A-B).

minmax(L,MIN,MAX) :- 
    L=[A|_], length(L,N), N2 is N-1,
    length(L2,N2), append(L2,[MIN],L22), 
    length(L3,N2), append(L3,[MAX],L33),
    maplist(pair, [A|L2], L22, KL2),
    maplist(pair, [A|L3], L33, KL3),
    maplist(is_minmax, L, KL2, KL3).

(SWI Prolog で動作します)。ドットの代わりに何を書くべきか考えてみてください...

于 2012-10-03T16:54:27.927 に答える
1

リストから最初の値を取得し、リストの他の各要素を調べて、より低い/より高い値を一時的な最小値/最大値として選択します。

リストの最後にある場合、両方を持っています...

minmax([First|Rest], Min, Max) :-
   minmax(Rest, First, First, Min, Max).

minmax([], Min, Max, Min, Max).
minmax([Value|Ns], MinCurr, MaxCurr, Min, Max) :-
   .... 
   minmax(Ns, MinNext, MaxNext, Min, Max).

再帰呼び出しの前にテストを書かせます (つまり、ドットを埋めます!)。

複数の Prolog システムで利用可能なライブラリ ( aggregate )を指摘するためだけに編集します。

1 ?- [user].
minmax(L, X, Y) :- aggregate( (min(E), max(E)), member(E, L), (X, Y) ).
|: 
true.

2 ?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10,
Y = 7.
于 2012-10-03T13:53:31.393 に答える