You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SWI-Prolog中按元组第二个元素排序并去重?

解决SWI-Prolog中按元组第二个元素排序并去重的问题

好问题!确实,标准的sort/2虽然能自动去重,但它是按元组的字典序(先比较第一个元素,再比较第二个)排序的,没法直接满足你按第二个元素排序的需求。这里有两种简洁的解决方案,都能帮你得到目标列表[(4,2), (1,4), (5,4), (3,12)]:

方法一:自定义排序规则(用sort/3)

SWI-Prolog提供了sort/3谓词,允许你自定义排序的比较逻辑。我们可以先通过sort/2去重,再用自定义规则按元组的第二个元素排序(第二个元素相同时,按第一个元素升序排列,和你的示例结果一致)。

代码实现:

% 定义自定义比较谓词:先比较元组的第二个元素,相同则比较第一个元素
compare_second(Order, (A1, A2), (B1, B2)) :-
    compare(Order, A2, B2),
    (A2 = B2 -> compare(Order, A1, B1) ; true).

% 主逻辑
solve(Original, Result) :-
    sort(Original, UniqueList),  % 第一步:去重,得到无重复的列表
    sort([order(compare_second)], UniqueList, Result).  % 第二步:按自定义规则排序

使用示例:

?- Original = [(5,4), (1,4), (3,12), (4,2), (5,4)], solve(Original, Result).
Original = [(5, 4),  (1, 4),  (3, 12),  (4, 2),  (5, 4)],
Result = [(4, 2),  (1, 4),  (5, 4),  (3, 12)].

方法二:键排序(用keysort/2)

另一种思路是把每个元组的第二个元素作为“排序键”,先转换元组的结构,用keysort/2按键排序,再转换回原结构。同样先通过sort/2去重,避免重复处理。

代码实现:

% 辅助谓词:交换元组的两个元素
swap((X, Y), (Y, X)).

% 主逻辑
solve(Original, Result) :-
    sort(Original, UniqueList),  % 第一步:去重
    maplist(swap, UniqueList, KeyList),  % 转换为(第二个元素,第一个元素)的形式
    keysort(KeyList, SortedKeys),  % 按键(原元组的第二个元素)排序
    maplist(swap, SortedKeys, Result).  % 转换回原元组结构

使用示例:

?- Original = [(5,4), (1,4), (3,12), (4,2), (5,4)], solve(Original, Result).
Original = [(5, 4),  (1, 4),  (3, 12),  (4, 2),  (5, 4)],
Result = [(4, 2),  (1, 4),  (5, 4),  (3, 12)].

说明:

  • keysort/2会按每个元素的第一个分量(也就是我们转换后的原元组第二个元素)排序,相同键的元素会保留它们在UniqueList中的相对顺序——而sort/2生成的UniqueList中,(1,4)本来就在(5,4)前面,所以最终结果和你的示例完全匹配。
  • 两种方法都先做去重,这样后续排序的元素更少,效率更高。

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:29:14