また、最小値と最大値 (最大損失と最小損失) を取得する関数も作成しました。
Prolog やその他の宣言型言語は、いくつかの驚くべき方法で手続き型言語とは異なります。そのうちの 1 つは、ある種のループ構造内から再利用することを予期して、作業の一部を頻繁に実行することは、正確には正しいアプローチではないということです。これは、常にセットの観点から処理する必要がある SQL ではより明らかに当てはまりますが、明示的なループ構造があまり使用されていない Prolog でも当てはまります。
手続き型環境で低得点チームと高得点チームを一致させる問題は、次のようなプロセスで解決するのが最適です。
def match(teams):
while we have teams:
remove the lowest scoring team from teams
remove the highest scoring team from teams
save this pair
return the list of pairs
これをより機能的にする簡単な方法は、再帰を使用することです。
def match(teams):
if teams is empty: return empty list
otherwise:
remove the lowest scoring team
remove the highest scoring team
return this pair appended to match(teams without these two items)
実際には、多くの労力を費やすことなく、これを適切な外観の Prolog に変換できます。
match([], []).
match(Teams, [Lowest-Highest|Pairs]) :-
lowest(Teams, Lowest),
highest(Teams, Highest),
select(Lowest, Teams, TeamsWithoutLowest),
select(Highest, TeamsWithoutLowest, RemainingTeams),
match(RemainingTeams, Pairs).
これは、リストのスキャンが何度も繰り返され、 内でリストの再構築が頻繁に行われるため、効率的ではない可能性がありますがselect/3
、より宣言的である可能性があります。
もう 1 つの方法は、チームのリストを並べ替えてから、それを元に戻して、最下位と最上位のペアを取得することです。視覚的に:
[1, 2, 3, 4, 5, 6]
[1, 2, 3], [4, 5, 6]
[1, 2, 3], [6, 5, 4]
[1, 2, 3]
[6, 5, 4]
-------------------
[1-6], [2-5], [3-4]
これは Prolog でいくらか直接行うことができますが、最初に 2 つのリストをペアにする方法が必要です。
pair_off([], _, []).
pair_off([L|Ls], [R|Rs], [L-R|Rest]) :- pair_off(Ls, Rs, Rest).
次に、アルゴリズムは次のように Prolog に進みます。
match_lowest_highest(SortedList, Pairs) :-
length(SortedList, N2),
N is N2 div 2,
length(TopHalf, N),
append(TopHalf, BottomHalf, SortedList),
reverse(BottomHalf, BottomHalfFlipped),
pair_off(TopHalf, BottomHalfFlipped, Pairs).
これはまだ非常に効率的ではありませんが、reverse/2
ビルトインはおそらく差分リストを使用しているため、それほど高価ではありません。append/3
すでに実体化された未知数のリストを使用することで、破棄される一時的なリスト構築の束を節約できます。したがって、これがひどく非効率的であるとは思いませんが、より効率的な方法が他にもあると確信しています。