【问题标题】:Combining two lists in prolog在序言中组合两个列表
【发布时间】:2021-03-13 02:03:50
【问题描述】:

你会如何组合两个列表?这是我尝试过的,但它没有给我想要的结果,

Y = [1,2,3].
Z = [3,4,5].
X = [Y,Z].

这只是给出了一个更大的列表,头尾分开。

我希望我的输出如下所示:

X = [1,2,3,4,5].

【问题讨论】:

  • 为了清楚起见,3 出现在两个列表中,但您只希望它在输出中出现一次?
  • @Enigmativity 是的,没错。我正在考虑像下面建议的答案一样附加并制作一个谓词来删除其中一个重复项。
  • 赏金文本应为:@gusbro 在/a/66450073 中的初始定义的纯版本。理想情况下还枚举length(Zs,_), combine(Xs, Ys, Zs). 的所有答案 失败为combine([a|_],_,[b|_]). &ct
  • @false 你会认为(@<)/2纯粹是为了你的赏金吗?
  • @IsabelleNewbie:a @< X 失败。然而,X = b, a @< X 成功了。您需要将其隐藏在一些干净的界面后面

标签: prolog


【解决方案1】:

如果您想将可能重叠的两个基本列表合并到第三个列表中,只保留重叠元素的一个副本(即第一个列表的后缀元素也形成第二个列表的前缀),您可以这样写:

combine(A, B, C):-
  append(A1, Common, A),
  append(Common, B1, B),
  !,  % The cut here is to keep the longest common sub-list
  append([A1, Common, B1], C).

样本运行:

?- combine([1,2,3],[3,4,5], C).
C = [1, 2, 3, 4, 5].

?- combine([1,2,3,4],[3,4,5], C).
C = [1, 2, 3, 4, 5].

稍作修改以避免使用剪切:

combine(A, B, C):-
  append(A1, Common, A),
  append(Common, B1, B),
  bagof(NotCommonA-NotCommonB,
        not_common(A1, B1, NotCommonA, NotCommonB),
        LDifs),
  maplist(difpair, LDifs),
  append([A1, Common, B1], C).
  
not_common(L, R, [ItemA|NotCommonA], NotCommonB):-
  append(_, [ItemA|NotCommonA], L),
  length([ItemA|NotCommonA], LNotCommon),
  length(NotCommonB, LNotCommon),
  append(NotCommonB, _, R).

difpair(L-R):-
  dif(L, R).

示例运行:

?- combine([1,2,3],[3,4,5], C).
C = [1, 2, 3, 4, 5] ;
false.

?- combine([1,2,3,X],[3,4,5], C).
X = 4,
C = [1, 2, 3, 4, 5] ;
X = 3,
C = [1, 2, 3, 3, 4, 5] ;
C = [1, 2, 3, X, 3, 4, 5],
dif(X, 3),
dif(X, 4) ;
;
false

【讨论】:

  • 我已经编辑和恢复,以展示一些东西。请问您有什么意见,这样的编码风格对新手学习有帮助吗?
  • @Will:用一种干净的方法来去除切口而不是标签?
  • @false:编辑答案中的方法怎么样?我想使用`foreach/2`,但至少在我的 SWI 中它创建了未绑定变量的副本,所以我最终选择了 bagof+maplist。
  • @false 嗯,有趣的挑战。我没有看到一种干净的(位置/结构)方式来做那个 atm。 :)
  • 显然是赏金的!
【解决方案2】:

这个问题完全不清楚:是关于合并排序列表吗?排序的数字列表,也许?它是关于一种只保留第二个列表的第一个列表/前缀的共享后缀的副本的附加吗?是不是更一般意义上的删除重复项?

这是一个删除共享后缀/前缀的解决方案。它类似于 slago 的解决方案,除了它使用两个谓词来表示计算可能处于的两种不同状态:merge“复制”从第一个参数到第三个参数的元素;在某些时候它切换到mergerest,它“继续复制”但要求它的第一个参数是第二个参数的非空前缀。

merge(Xs, Ys, Zs) :-
    mergerest(Xs, Ys, Zs).
merge([X|Xs], [Y|Ys], [X|Zs]) :-
    merge(Xs, [Y|Ys], Zs).

mergerest([X], [X|Ys], [X|Ys]).
mergerest([X|Xs], [X|Ys], [X|Zs]) :-
    mergerest(Xs, Ys, Zs).

使用 false 的动物定义:

?- animal(A), animal(B), dif(A, Mutation), merge(A, B, Mutation).
A = [a,l,l,i,g,a,t,o,r],
B = [t,o,r,t,u,e],
Mutation = [a,l,l,i,g,a,t,o,r,t,u,e] ;
A = [c,a,r,i,b,o,u],
B = [o,u,r,s],
Mutation = [c,a,r,i,b,o,u,r,s] ;
A = [c,h,e,v,a,l],
B = [a,l,l,i,g,a,t,o,r],
Mutation = [c,h,e,v,a,l,l,i,g,a,t,o,r] ;
A = [c,h,e,v,a,l],
B = [l,a,p,i,n],
Mutation = [c,h,e,v,a,l,a,p,i,n] ;
A = [v,a,c,h,e],
B = [c,h,e,v,a,l],
Mutation = [v,a,c,h,e,v,a,l] ;
false.

仅绑定第三个参数的行为,例如:

?- merge(Xs, Ys, [1, 2, 3]).
Xs = [1],
Ys = [1, 2, 3] ;
Xs = [1, 2],
Ys = [1, 2, 3] ;
Xs = Ys, Ys = [1, 2, 3] ;
Xs = [1, 2],
Ys = [2, 3] ;
Xs = [1, 2, 3],
Ys = [2, 3] ;
Xs = [1, 2, 3],
Ys = [3] ;
false.

更笼统地说:

?- length(Zs,_), merge(Xs, Ys, Zs).
Zs = Xs, Xs = Ys, Ys = [_4262] ;
Zs = Ys, Ys = [_4262, _4268],
Xs = [_4262] ;
Zs = Xs, Xs = Ys, Ys = [_4262, _4268] ;
Zs = Xs, Xs = [_4262, _4268],
Ys = [_4268] ;
Zs = Ys, Ys = [_4262, _4268, _4274],
Xs = [_4262] ;
Zs = Ys, Ys = [_4262, _4268, _4274],
Xs = [_4262, _4268] ;
Zs = Xs, Xs = Ys, Ys = [_4262, _4268, _4274] ;
Zs = [_4262, _4268, _4274],
Xs = [_4262, _4268],
Ys = [_4268, _4274] ;
Zs = Xs, Xs = [_4262, _4268, _4274],
Ys = [_4268, _4274] ;
Zs = Xs, Xs = [_4262, _4268, _4274],
Ys = [_4274] ;
Zs = Ys, Ys = [_4262, _4268, _4274, _4280],
Xs = [_4262] ;
Zs = Ys, Ys = [_4262, _4268, _4274, _4280],
Xs = [_4262, _4268] .  % ad nauseam

快速失败:

?- merge([a|_],_,[b|_]).
false.

【讨论】:

  • merge("iguana","anaconda",L). 有两种解决方案,而不是一种。
  • @false 是的。太糟糕了,没有规范告诉我们需要什么。
  • 查看接受的答案。显然这是规范!
【解决方案3】:

以下是对这个问题的另一种看法:

combine([A|As], [B|Bs], [A|Cs]):-
  dif(A, B),
  combine(As, [B|Bs], Cs).
combine(As, Bs, Cs):-
  suffix_prefix(As, Bs, Cs).
combine([A|As], [A|Bs], [A|Cs]):-
  not_suffix_prefix(As, Bs, Cs),
  combine(As, [A|Bs], Cs).
  
suffix_prefix([], Bs, Bs).
suffix_prefix([A|As], [A|Bs], [A|Cs]):-
  suffix_prefix(As, Bs, Cs).

not_suffix_prefix([_|_], [], [_|_]).
not_suffix_prefix([A|As], [A|Bs], [_|Cs]):-
  not_suffix_prefix(As, Bs, Cs).
not_suffix_prefix([A|_], [B|_], _):-
  dif(A, B).

示例运行(来自测试答案),combine([a|_], _, [b|_]) 失败,生成所有解决方案和一些其他测试:

?- mutation(C).
C = [a, l, l, i, g, a, t, o, r, t, u, e] ;
C = [c, a, r, i, b, o, u, r, s] ;
C = [c, h, e, v, a, l, l, i, g, a, t, o, r] ;
C = [c, h, e, v, a, l, a, p, i, n] ;
C = [v, a, c, h, e, v, a, l] ;
false.

?- combine([a|_], _, [b|_]).
false.

?- combine([1,2,3], [3,4,5], Cs).
Cs = [1, 2, 3, 4, 5] ;
false.

?- combine([1,2,3,X], [3,4,5], Cs).
X = 4,
Cs = [1, 2, 3, 4, 5] ;
Cs = [1, 2, 3, '$VAR'('X'), 3, 4, 5],
dif('$VAR'('X'), 3),
dif('$VAR'('X'), 4) ;
;
X = 3,
Cs = [1, 2, 3, 3, 4, 5] ;
false.

?- combine([A,A], [A], C).
C = ['$VAR'('A'), '$VAR'('A')] ;
false.

?- length(Zs, Len), combine(Xs, Ys, Zs).
Zs = Xs, Xs = Ys, Ys = [],
Len = 0 ;
Zs = Ys, Ys = [_2419916],
Len = 1,
Xs = [] ;
Zs = Xs, Xs = Ys, Ys = [_2419916],
Len = 1 ;
Zs = [_2420492, _2420498],
Len = 2,
Xs = [_2420492],
Ys = [_2420498],
dif(_2420492, _2420498) ;
;
Zs = Xs, Xs = [_2420498, _2420504],
Len = 2,
Ys = [_2420504],
dif(_2420498, _2420504) ;
;
Zs = Ys, Ys = [_2419916, _2419922],
Len = 2,
Xs = [] ;
Zs = Ys, Ys = [_2419916, _2419922],
Len = 2,
Xs = [_2419916] ;
Zs = Xs, Xs = Ys, Ys = [_2419916, _2419922],
Len = 2 ;
Zs = Xs, Xs = [_2419916, _2419916],
Len = 2,
Ys = [_2419916] ;
Zs = [_2420690, _2420696, _2420702],
Len = 3,
Xs = [_2420690, _2420696],
Ys = [_2420702],
dif(_2420690, _2420702),
dif(_2420696, _2420702) ;

.... continues ...

【讨论】:

  • 那么combine([1,2,3,X],[3,4,5], C). 在您的第一个答案中呢,我们也可以在这里看到它的结果以进行比较吗?
  • @WillNess:运行该示例我发现combine/3 的基本情况存在问题(缺少一些解决方案)。修复了这个问题并重新运行所有样本,包括我从第一个答案运行的样本。
  • 正如我在回答中指出的那样,我认为这个调用应该成功:combine2([A,A],[A],C) 但不符合您的谓词(除非我误解了定义)。
  • @jnmonette:现在它工作正常。当“后缀”以“前缀”开头但更长时,我需要在 not_suffix_prefix/3 中添加一个子句
  • 这个'$VAR'('X')来自哪里?
【解决方案4】:

这是一个测试程序(自 Meloni,1976 年以来),已简化以避免转换和琐碎的解决方案。请参阅iwhen/2 的定义并将字符打印为double quoted strings 在答案替换中。

:- set_prolog_flag(double_quotes, chars).

animal("alligator").
animal("tortue").
animal("caribou").
animal("ours").
animal("cheval").
animal("vache").
animal("lapin").
% animal("iguana").
% animal("anaconda").

mutation(C) :-
   animal(A),
   animal(B),
   dif(A, C),
   combine(A, B, C),
   iwhen(ground(A+B+C), \+ append(A, B, C) ).

?- mutation(C).
   C = "alligatortue"
;  C = "caribours"
;  C = "chevalligator"
;  C = "chevalapin"
;  C = "vacheval"
;  false.

【讨论】:

    【解决方案5】:

    这是另一种解决方案,与 gusbro 的解决方案相对相似,但修复了一些缺失的情况(例如,combine([A,A],[A],C) 应该成功,C=[A,A])。

    % Third is the concatenation of First and Second but without the longest suffix
    combine(As,Bs,Bs):-         %     of First that is also a prefix of Second
        prefix(As,Bs).
    combine([A|As],Bs,[A|Cs]):-
        prefix(As, Cs),         % Necessary when As is var to avoid
        not_prefix([A|As], Bs), %          generating too long lists
        combine(As,Bs,Cs).
    
    % First is prefix of Second
    prefix([],_).
    prefix([A|As],[A|Bs]):-
        prefix(As,Bs).
    
    % First is not prefix of Second
    not_prefix(As,Bs):-
        longer(As,Bs).
    not_prefix(As,Bs):-
        not_longer(As,Bs),
        not_prefix2(As,Bs).
    
    % First is not prefix of Second, knowing it is not longer
    not_prefix2([A|As],[A|Bs]):-
        not_prefix2(As,Bs).
    not_prefix2([A|_],[B|_]):-
        dif(A,B).
    
    % First is longer than Second
    longer([_|_], []).
    longer([_|As],[_|Bs]):-
        longer(As,Bs).
    
    % First is not longer than Second
    not_longer([], _).
    not_longer([_|As],[_|Bs]):-
        not_longer(As,Bs).
    

    一些测试:

    ?- combine([1,2,3], [3,4,5], Cs).
    Cs = [1,2,3,4,5] ? ;
    no
    
    ?- combine([1,2,3,X], [3,4,5], Cs).
    X = 4,
    Cs = [1,2,3,4,5] ? ;
    X = 3,
    Cs = [1,2,3,3,4,5] ? ;
    Cs = [1,2,3,X,3,4,5],
    prolog:dif(X,4),
    prolog:dif(X,3) ? ;
    no
    
    ?- combine([a|_], _, [b|_]).
    no
    
    ?- length(Cs, Len), combine(As, Bs, Cs).
    Cs = [],
    Len = 0,
    As = [],
    Bs = [] ? ;
    Cs = [_A],
    Len = 1,
    As = [],
    Bs = [_A] ? ;
    Cs = [_A],
    Len = 1,
    As = [_A],
    Bs = [_A] ? ;
    Cs = [_A],
    Len = 1,
    As = [_A],
    Bs = [] ? ;
    Cs = [_A,_B],
    Len = 2,
    As = [],
    Bs = [_A,_B] ? ;
    Cs = [_A,_B],
    Len = 2,
    As = [_A],
    Bs = [_A,_B] ? ;
    Cs = [_A,_B],
    Len = 2,
    As = [_A,_B],
    Bs = [_A,_B] ? ;
    Cs = [_A,_B],
    Len = 2,
    As = [_A],
    Bs = [_B],
    prolog:dif(_A,_B) ? ;
    Cs = [_A,_B],
    Len = 2,
    As = [_A,_B],
    Bs = [] ? ;
    Cs = [_A,_B],
    Len = 2,
    As = [_A,_B],
    Bs = [_B] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [],
    Bs = [_A,_B,_C] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A],
    Bs = [_A,_B,_C] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B],
    Bs = [_A,_B,_C] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B,_C],
    Bs = [_A,_B,_C] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A],
    Bs = [_B,_C],
    prolog:dif(_A,_B) ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B],
    Bs = [_C],
    prolog:dif(_B,_C) ? ;
    Cs = [_A,_A,_B],
    Len = 3,
    As = [_A,_A],
    Bs = [_A,_B],
    prolog:dif(_A,_B) ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B],
    Bs = [_B,_C],
    prolog:dif(_A,_B) ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B,_C],
    Bs = [] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B,_C],
    Bs = [_C] ? ;
    Cs = [_A,_B,_C],
    Len = 3,
    As = [_A,_B,_C],
    Bs = [_B,_C] ? ;
    Cs = [_A,_B,_C,_D],
    Len = 4,
    As = [],
    Bs = [_A,_B,_C,_D] ? 
    yes
    

    【讨论】:

      【解决方案6】:

      prolog 并不是这样工作的(你所做的并不是你想象的赋值)。

      但无论如何,以下是附加两个列表的方法:

      ?- append([1,2,3],[3,4,5],X).
      returns: X = [1, 2, 3, 3, 4, 5].
      

      【讨论】:

      • 正如 gusbro 在下面指出的,您可能还对两个列表的 union 感兴趣:union( [1,2,3], [3,4,5], X). 返回 X = [1,2,3,4,5]
      • 但是union( [1,2,3], [5,3,4,5], X) ==> X = [1, 2, 5, 3, 4, 5] 而不是X = [1, 2, 3, 5, 3, 4, 5]
      • @WillNess 确实如此,但这仅在这一点上相关,因为到目前为止,这个问题已经被重新解释了大约 3 倍的复杂程度。在一个有效地证明提问者仍在试图理解统一和分配之间的有效区别的问题上:p
      【解决方案7】:

      一个可能的解决方案是:

      combine([], B, B).
      combine(A, [], A).
      combine([X|A], [X|B], [X|C]) :- combine(A, B, C).
      combine([X|A], [Y|B], [X|C]) :- dif(X,Y), combine(A, [Y|B], C).
      

      一些查询:

      ?- combine([1,2,3,4,5], [3,4,5,6,7], C).
      C = [1, 2, 3, 4, 5, 6, 7] ;
      false.
      
      ?- combine([1,2,3,4,5], [4,5,6,7], C).
      C = [1, 2, 3, 4, 5, 6, 7] ;
      false.
      
      ?- combine([1,2,3,4,5], [5,6,7], C).
      C = [1, 2, 3, 4, 5, 6, 7] ;
      false.
      
      ?- combine([1,2,3,4,5], [6,7], C).
      C = [1, 2, 3, 4, 5, 6, 7] ;
      false.
      
      ?- combine([1,2,3,4,5], [], C).
      C = [1, 2, 3, 4, 5] ;
      false.
      
      ?- combine([], [3,4,5,6,7], C).
      C = [3, 4, 5, 6, 7] ;
      false.
      

      【讨论】:

      • combine("vacheval","vel","vacheval"). 成功失败
      • 在问题中的一个 cmets 中,提问者说:“我正在考虑附加 (...) 并创建一个谓词来删除其中一个重复项”。因此,对于提问者提出的问题,我认为答案是正确的。
      • 含义 - 至少对于赏金 - 由 gusbro 的第一个定义给出。而且,“删除其中一个重复项”显然也不是一个精确的要求,我想知道在上面的案例中实际删除了什么。
      • @false 我在回答问题时不打算接受赏金。至于被删除的内容,很容易看出[v, a, c, h, e, v, a, l]包含[v, e, l],那么删除的项目分别是vel
      猜你喜欢
      • 1970-01-01
      • 2010-10-02
      • 2011-11-29
      • 2017-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多