【问题标题】:Prolog: expressing that two lists have at least two elements in commonProlog:表示两个列表至少有两个共同元素
【发布时间】:2015-12-10 04:58:20
【问题描述】:

我试图找出两个列表是否重叠。我想写的谓词 接受两个列表,如果列表至少有两个共同元素,则返回 true。

具有预期答案的示例查询:

?- overlap([13,14,15], [17,18,13,19]).
false.

?- overlap([13,14,15], [14,17,13,18,16]).
true.

但是,到目前为止,我只有一个元素可以工作。

member(M, [M|_]).
member(M, [_|T]) :-
   member(M, T).

overlap(X, Y) :-
   member(M, X),
   member(M, Y).

?- overlap([a,b,c,d], [1,2,c,d]).

如何确保它检查两个元素,而不仅仅是一个?

【问题讨论】:

    标签: list prolog


    【解决方案1】:

    另一种与您的代码非常接近的方法是确保两个成员不相同:

    overlap(X, Y) :-
        dif(A, B),
        member(A, X), member(A, Y),
        member(B, X), member(B, Y).
    

    由于有评论要求以更有效的方式执行此操作,因此这里有一种完全不同的方法,如 this answer to a very similar question

    overlap(N, X, Y) :-
        sort(Xs, SX),
        sort(Ys, SY),
        append(SX, SY, All), length(All, Len_all),
        sort(All, Sorted), length(Sorted, Len_sorted),
        Len_sorted =< Len_all - 2.
    

    简单来说,由于 sort 还会删除所有重复项,因此可以通过比较排序前后的长度来计算列表中的重复项数。一旦以这种方式编写谓词,您还会注意到您可以对其进行一些概括,以便它有两个参数:一个列表列表和一个非负整数,它是所有列表之间共享的元素数:

    overlap_n(LL, N) :-
        maplist(sort, LL, SLL), % sort all lists
        append(SLL, All), length(All, Len_all),
        sort(All, Sorted), length(Sorted, Len_sorted),
        N is Len_all - Len_sorted.
    

    您现在可以将您原来的问题表达为:

    ?- overlap_n([X, Y], N), N >= 2.
    

    【讨论】:

    • 不错,但这不能更有效率吗?
    • @false 效率会高很多。
    【解决方案2】:

    如果您的 Prolog 有 intersection/3,则较短的形式可能是:

    overlap(X,Y) :- intersection(X,Y,[_,_|_]).
    

    对于大型的重叠列表来说,这将是低效的。您的方法很容易纠正和扩展:

    overlap(X,Y) :-
        select(A,X,Rx), select(A,Y,Ry),
        member(B,Rx), member(B,Ry).
    

    我会在末尾添加一个剪辑以避免多种解决方案...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多