我还编写了一个函数来获取最小值和最大值(最高和最低损失)。
Prolog 和其他声明性语言在一些令人惊讶的方面不同于过程语言,其中之一是经常做一些工作以期望从某种循环结构中重用它并不是完全正确的方法。这在 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, 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 中执行此操作,但首先我们需要一种方法来配对两个列表:
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
已经物化的未知数列表,我们节省了一堆临时列表结构,这些结构将被丢弃。所以我不认为这会非常低效,但我相信还有其他方法可以做到这一点,效率更高。