这是关于在Prolog中按特定参数对项进行排序而不创建新列表
假设我们希望
现在假设我们想要使用
然而,这与上面使用keysort/2的sort_argn/3并不相同。它将删除重复项,并且如果两个术语的第二个参数相等,则将按照原始完整术语的标准顺序排序复合术语:
假设对于每一对传递给比较谓词
现在,当两个“键”相等时,
keysort
的问题的一个答案后续。假设我们希望
predsort/3
的行为与sort/2
完全相同:如果我理解正确,这意味着将其调用为:?- predsort(compare, List, Sorted).
现在假设我们想要使用
msort/2
实现的方式来使用predsort/3
进行排序(参见此问题)。一种方法是定义一个比较谓词Pred(-Delta, +A, +B)
,当元素实际上相等时不使用=
统一Delta
:mcompare(Delta, A, B) :-
compare(Delta0, A, B),
( Delta0 == (=)
-> Delta = (<)
; Delta = Delta0
).
?- predsort(mcompare, List, Sorted).
问题: 它是否只是简单地进行排序而不删除重复项,就像msort/2
一样?它似乎应该这样。
接下来:假设我们想按术语的arity > n对术语进行排序,按照术语中第n个参数的标准顺序进行排序。最好的方法是:
sort_argn(N, List, Sorted) :-
map_list_to_pairs(arg(N), List, Pairs),
keysort(Pairs, Sorted_pairs),
pairs_values(Sorted_pairs, Sorted).
如果我们想要使用predsort/3
来实现相同的效果,我们可以尝试使用比较谓词如下:
compare_argn(N, Delta, A, B) :-
arg(N, A, AN),
arg(N, B, BN),
compare(Delta, AN-A, BN-B).
要按第二个参数进行排序:
?- predsort(compare_argn(2), List, Sorted).
然而,这与上面使用keysort/2的sort_argn/3并不相同。它将删除重复项,并且如果两个术语的第二个参数相等,则将按照原始完整术语的标准顺序排序复合术语:
?- predsort(compare_argn(2), [f(b,2), f(a,1), f(a,1), f(a,2)], Sorted).
Sorted = [f(a, 1), f(a, 2), f(b, 2)].
?- sort_argn(2, [f(b,2), f(a,1), f(a,1), f(a,2)], Sorted).
Sorted = [f(a, 1), f(a, 1), f(b, 2), f(a, 2)].
假设对于每一对传递给比较谓词
Pred(Delta, A, B)
的 A
和 B
,A
在原始列表中在B
之前。我们能否定义一个比较关系:compare_argn_stable(N, Delta, A, B) :-
arg(N, A, AN),
arg(N, B, BN),
compare(Delta0, AN, BN),
( Delta0 == (=)
-> Delta = (<)
; Delta = Delta0
).
在这一点上,仅当且仅当任何两个元素 A
和 B
总是按照它们在原始列表中的顺序传递给比较谓词时,这应该表现与上面的 sort_argn/3
相同:
?- predsort(compare_argn_stable(N), List, Sorted).
现在,当两个“键”相等时,
compare_argn_stable/4
将Delta
统一为<
是非常重要的。此外,其行为取决于实现,并且仅在predsort/3
将元素传递到比较谓词时保留原始顺序时才与keysort
示例相同。
问题:这样正确吗?
问题:是否有任何标准涵盖了predsort/3
的这个方面?
predsort/3
是一个伪稳定排序:它是一个归并排序,当比较返回=
时会丢弃一个元素。归并排序没有理由这样做,也没有理由在比较期间交换元素的顺序。如果我没错的话,快速排序有很多机会交换元素,因此它并不是“稳定”的。 - user1812457predsort/3
在其他几个Prolog实现中也可以找到。还有在Logtalk中(作为sort/3
)。希望能尽快实现我建议的优化。 - Paulo Moura