【问题标题】:Prolog: Build a list with repeated elements of other listProlog:用其他列表的重复元素构建一个列表
【发布时间】:2015-10-16 22:32:31
【问题描述】:

我需要构造一个接收列表的谓词,检查谁是重复元素并返回其他列表。示例:

?- rep_elements([a,b,c,a,b,d], Xs).
Xs = [a,b].

我开始构建一个基本结构,但我现在不知道如何完成这个谓词,或者如果这是更好的方法:

exists(Elem, [Elem|_]).
exists(Elem, [H|T]) :-
    exists(Elem, T).

rep_elements([], []).
rep_elements([H|T], [Y|Z]) :-
    exists(H, T),
    rep_elements(T, Z).

有什么建议吗?

【问题讨论】:

标签: list prolog


【解决方案1】:

首先,我建议我们使用更具描述性的谓词名称,list_uniqdups

我们根据 tpartition/4if_/3(=)/3 定义list_uniqdups/2

list_uniqdups([],[]).
list_uniqdups([X|Xs0],Ys0) :-
   tpartition(=(X),Xs0,Es,Xs),
   if_(Es=[], Ys0=Ys, Ys0=[X|Ys]),
   list_uniqdups(Xs,Ys).

示例查询:

?- list_uniqdups([a,b,c,a,b,d],Xs)。 OP 给出的 % 查询 Xs = [a,b]。 % 预期结果 ?- list_uniqdups([a,c,b,a,b,d],Xs)。 % 相似查询 Xs = [a,b]。 % 相同的结果 ?- list_uniqdups([b,c,a,a,b,d],Xs)。 % 现在,`b` 出现在 `a` 之前 Xs = [b,a]。 % 保留原订单 ?- list_uniqdups([a,a,a,a,b],Xs)。 Xs = [a]。 % 删除 所有 个重复项

请注意,以上所有查询都是确定性成功的。

【讨论】:

  • @false。突出显示好吗? (应该比以前更体面一些)
  • 这是一个非常有趣的解决方案。我将更仔细地研究元谓词,以了解是什么使这个解决方案成为可能。谢谢!
  • @RodrigoE。无论如何!元谓词支持惯用的高级编程风格。对于元谓词,我建议您首先查看maplist/2(更多信息:stackoverflow.com/a/6683502/4609915complang.tuwien.ac.at/ulrich/iso-prolog/prologue#maplist)。了解如何使用它以及它是如何工作的。那就回来学习tpartition/4
【解决方案2】:

让我们一步一步地重新编写您的代码!

  1. 谓词exists/2 被广泛使用的member/2 覆盖。让我们使用那个一个!

    代表元素([],[])。 代表元素([H|T],[Y|Z]):- 成员(H,T), 代表元素(T,Z)。
  2. As @CapelliC said, rep_elements/2 缺少一个子句;我们使用non_member/2添加一个!

    rep_elements([H|T], Z) :- 非成员(T,H), 代表元素(T,Z)。
  3. 让我们重新运行 OP 给出的查询!

    ?- rep_elements([a,b,c,a,b,d],Xs)。 Xs = [a,b] ;错误的。
  4. 好的!我们完了吗?不完全的!考虑以下查询和我们得到的答案:

    ?- rep_elements([a,a,a,a,b],Xs)。 Xs = [a,a,a] % (1) 重复项被保留 ; Xs = [a,a,a] % (2) 多余的答案 ; Xs = [a,a,a] % (2) ; Xs = [a,a,a] % (2) ; Xs = [a,a,a] % (2) ; Xs = [a,a,a] % (2) ;错误。 % (3) 留下无用的选择点
  5. 下一步是什么?退后一步,制定规范!

【讨论】:

  • 只是为了解释一下,我通常使用自己的谓词(exists/2 而不是member/2 等等),因为这样我可以在调试时逐步检查谓词运行,什么是' t 可能使用内置谓词。
【解决方案3】:

rep_elements/2 缺少对非重复元素的处理。

如果 exists/2 在删除找到的重复项后也会“返回”列表 T,那么我们可以使用清理后的列表进行递归,任务就完成了。当然,exists/2 应该变成 exists/3,并且可能重命名为更好、更具描述性的名称。

【讨论】:

    【解决方案4】:

    您可以递归检查列表的头部是否在列表的尾部,然后将其添加到 Result。 您的解决方案可以修改为:

    exists(Elem, [Elem|_]).
    exists(Elem, [H|T]) :-
         exists(Elem, T).
    /* IF you get empty list*/
    rep_elements([], []).
    
    /* If repetition found in list then joining it to head of list*/
    rep_elements([H|T], Result) :-
         exists(H, T),
         rep_elements(T, [H|Result]).
    
    /* If head of list is not found in the Tail of list*/
    rep_elements(H|T, Result):-
         not(exists(H,T)),
         rep_elements(T,Result).
    

    这应该可行。

    【讨论】:

      猜你喜欢
      • 2021-02-24
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      相关资源
      最近更新 更多