通过仿函数中的第二个原子对列表进行排序

时间:2015-01-21 15:10:53

标签: list sorting prolog

我在prolog中有这个列表:

List = [functor(a,1),functor(n,7),functor(l,9),functor(k,0)]

我希望按仿函数中的数字而不是字母对其进行排序。 我是说如果我这样做 sort(L,L1) 我会得到

L1 = [functor(a,1),functor(k,0),functor(l,9),functor(n,7)]

但我希望它像

L1 = [functor(k,0),functor(a,1),functor(n,7),functor(l,9)]

有没有办法做到这一点(而不仅仅是重新创建它并将数字放在第一位)

1 个答案:

答案 0 :(得分:4)

To"重新创建"清单(种类):

?- List = [functor(a,1),functor(n,7),functor(l,9),functor(k,0)],
    map_list_to_pairs(arg(2), List, Pairs),
    keysort(Pairs, Sorted_pairs),
    pairs_values(Sorted_pairs, Sorted).
Pairs = [1-functor(a, 1), 7-functor(n, 7), 9-functor(l, 9), 0-functor(k, 0)],
Sorted = [functor(k, 0), functor(a, 1), functor(n, 7), functor(l, 9)].

here。这可能是最常见的"惯用的"这样做的方法,因为你的实现有一个library(pairs)。如果它没有,那么这里使用的谓词几乎无关紧要:请参阅library source

如果您使用predsort,请参阅评论中也链接的the question。您可以定义辅助谓词,如:

compare_2(Order, A, B) :-
    arg(2, A, A2),
    arg(2, B, B2),
    compare(Order, A2-A, B2-B).

(由@false修正)

这将首先对第二个参数进行排序,如果它们相等,则在整个术语上进行排序。

?- List = [f(a,1),f(n,0),f(l,9),f(k,0)],
predsort(compare_2, List, Sorted).
List = [f(a, 1), f(n, 0), f(l, 9), f(k, 0)],
Sorted = [f(k, 0), f(n, 0), f(a, 1), f(l, 9)].

换句话说,它不是一个稳定的排序"。实际上,最好使用keysort方法。

请注意,此版本的compare_2仍会删除除第一次出现的相同字词之外的所有字词,因为这是predsort所做的:

?- List = [f(a,1),f(n,0),f(l,9),f(n,0)],
predsort(compare_2, List, Sorted).
List = [f(a, 1), f(n, 0), f(l, 9), f(n, 0)],
Sorted = [f(n, 0), f(a, 1), f(l, 9)].

你可以"作弊"通过定义两个等效(但不相等)的元素已经排序:

compare_2_stable(Order, A, B) :-
    arg(2, A, A2),
    arg(2, B, B2),
    compare(Order0, A2, B2),
    (   Order0 == (=)
    ->  Order = (<)
    ;   Order = Order0
    ).

?- List = [f(a,1),f(n,0),f(l,9),f(k,0)],
predsort(compare_2_stable, List, Sorted).
List = [f(a, 1), f(n, 0), f(l, 9), f(k, 0)],
Sorted = [f(n, 0), f(k, 0), f(a, 1), f(l, 9)].

?- List = [f(a,1),f(n,0),f(l,9),f(n,0)],
predsort(compare_2_stable, List, Sorted).
List = [f(a, 1), f(n, 0), f(l, 9), f(n, 0)],
Sorted = [f(n, 0), f(n, 0), f(a, 1), f(l, 9)].

请注意,我不确定这是否真的会保留等效元素的原始顺序(元素与&#34;相等&#34;第二项)。就这个例子而言,它现在就是这样做的。只有当predsort将元素传递给比较谓词时,它们才会保持原始顺序,这可能就是这种情况,这可能取决于实现(??)。

编辑:在SWI-Prolog中查看了predsort/3的源代码,是的,在SWI-Prolog中,使用当前的实现,最后的解决方案将提供完全相同的解决方案使用keysort/2但是,除非您有实际的理由,否则您应该更喜欢keysort/2,并且您愿意牺牲可移植性。