【问题标题】:Check if element in a list of lists is equal prolog检查列表列表中的元素是否相等序言
【发布时间】:2019-07-02 14:36:44
【问题描述】:

我正在尝试检查列表列表中的所有子列表是否等于列表列表的长度。

例如,如果我有 [[1,2],[3,4]] 为真,因为我有 2 个列表 2 个元素。

否则,如果我有

[[1],[2,3]] 为假,因为有 2 个列表但并非所有列表都有 2 元素

[[1,2],[2,3],[3,4]] 是错误的,因为我有 2 个列表并且所有列表都有 2 个元素而不是 2 个

.

我做了这两个功能:

count([],0).
count([_H|T],N):-count(T,N1),N is N1+1 .

ma([],0).
ma([H|T],N):- count(H,M1),ma(T,N1), M1 is N1.

我对列表中的计数元素进行了“计数”(并工作)并返回列表中元素的数量。

“ma”函数不起作用,因为“count”执行到0,返回2,执行ma后直到1步,直接使M1为N1,显然返回false。 我希望在程序结束时使 M1 为 N1(就像在另一种编程语言中一样,但我认为这是不正确的形式。

编辑:

Daniel 建议使用:

ma([H],   N) :- length(H, N).
ma([H|T], N) :- length(H, N), ma(T, N).

但是一个包含 3 个子列表的列表都包含 2 个元素会给出结果 2,而不是结果将是 false(错误),因为列表的 N 个必须等于所有子列表中的 N 个元素。

我会自己做,没有 prolog 的内置谓词。

【问题讨论】:

  • 我叫丹尼尔,不是大卫。

标签: prolog


【解决方案1】:

这是一个非常基本的解决方案,没有内置谓词:

count_elements([],N,N).
count_elements([_|T],N,N0):-
    N1 is N+1,
    count_elements(T,N1,N0).

count_length_sub([],_).
count_length_sub([H|T],N):-
    count_elements(H,0,N),
    count_length_sub(T,N).

solve(L):-
    count_elements(L,0,NO),
    count_length_sub(L,NO).

?- solve([[1,2],[3,4]]).
true.

?- solve([[1,2],[2,3],[3,4]]).
false.

【讨论】:

  • 非常感谢!我也明白其中的道理!
  • 首选succ/2 而不是... is X+1,因为它有更多的实例化。
【解决方案2】:

您的count/2 类似于length/2 内置,除了内置有更多的实例化模式(尝试length(X, Y) 并查看)。首选length/2

你是对的,你的 ma/2 谓词没有帮助,因为 0 不是子列表的长度。基本上,您在这里选择了错误的基本情况;您的基本案例应该是一个列表,其中只有一个项目:

ma_1([H],   N) :- length(H, N).
ma_1([H|T], N) :- length(H, N), ma(T, N).

您需要将其包装在确保长度与外部列表长度匹配的东西中:

ma(L, N) :- length(L, N), ma_1(L, N).

请注意,无需获取单独的变量并断言它们的相等性(您与 N 和 N1 共舞)。如果 N 没有正确的值,Prolog 将简单地失败,这就是您想要的。 (旁注,不要使用is来统一。is的目的是将右侧的算术表达式归约为一个值并将其分配给左侧的变量,例如X is 2 + 3*4。)

另一种方法是以逻辑形式编写您的实际请求并改为编写。此请求的逻辑形式类似于“如果 N 是 L 的长度,并且对于 L 的所有项目 X,它们也是长度为 N 的列表,则 ma(L, N) 成立”。看起来像这样:

ma(L, N) :- 
    length(L, N), 
    forall(member(X, L), 
           length(X, N)).

这样做的好处是没有多余的选择点,尽管担心这通常是过早的优化。

另一种方法是使用maplist/N,它的优点是可以为您提供带有变量的后备列表。不幸的是,length/2 的参数顺序错误,所以你不能做真正可爱的事情,只写maplist(length(2), L)。但是,您可以创建一个围绕参数翻转的 flip/3 谓词:

flip(P, Y, X) :- call(P, X, Y).

ma(L, N) :- length(L, N), maplist(flip(length, N), L).

或者,您可以导入 library(yall) 并使用其 lambda 表达式:

ma(L, N) :- length(L, N), maplist({N}/[X]>>length(X, N), L).

这两种方法都允许这样的解决方案:

?- ma(X, N).
X = [],
N = 0 ;

X = [[_1976]],
N = 1 ;

X = [[_1982, _1988], [_1994, _2000]],
N = 2 ;

X = [[_1988, _1994, _2000], [_2006, _2012, _2018], [_2024, _2030, _2036]],
N = 3 
...

【讨论】:

  • 用地图列表代替 forall 也可以处理 ma(L,2)
  • @false 我正在考虑这个问题,但我认为length/2 的参数与maplist(length(2), L) 的顺序错误。还有其他方法吗?
  • @DanielLyons:是的,您可以使用 lambda 表达式。然而,遗憾的是,afaik,没有flip 谓词。
  • Ehy Daniel,感谢您的回答。您使用了我不使用的更复杂的谓词。我知道长度/2 内置,但我必须独自完成,因为我的教授不希望我们使用谓词内置:S 我试过你 ma/2 但不要和我的员工一起工作,因为当你打电话给 ma 时工作( [1,2],[2,3],[3,4],X) 给出 2...这是错误的,因为必须失败...我将编辑我的问题
  • @theantomc 我添加了一个小包装来防止这个问题。
猜你喜欢
  • 2013-09-19
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多