测试列表中的所有列表是否具有相同的长度

时间:2012-02-15 21:05:45

标签: list prolog

我正在尝试更多地了解Prolog中的列表,尤其是列表中的列表。所以我想编写一个谓词来确定列表中的列表是否相等。所以,如果我这样做了

?- equalLists([[a,b,c],[1,2,3],[d,4,e],[5,6]]).
false

所以我试图检查每个列表,看它是否与前一个列表的长度相同。有人能指出我正确的方向吗?

8 个答案:

答案 0 :(得分:4)

首先,我们定义一些标准的高阶关系,mapfold。这需要内置的call谓词。可以将maxlist等定义为一次性,但这应该更具启发性。

我们的想法是获取一个长度列表,然后比较列表中的最大数量是否等于最小值。

maplist(_, [], []).
maplist(P, [X | Y], [A | B]) :-
  call(P, X, A),
  maplist(P, Y, B).

max(A, B, M) :- A <  B, M = B.
max(A, B, M) :- A >= B, M = A.

min(A, B, M) :- B <  A, M = B.
min(A, B, M) :- B >= A, M = A.

fold(_, [X], X).
fold(P, [X, Y], R) :- call(P, X, Y, R).
fold(P, [X, Y | Z], R) :-
  fold(P, [Y | Z], NR),
  call(P, NR, X, R).

maxlist(L, M) :- fold(max, L, M).

minlist(L, M) :- fold(min, L, M).

equallists(L) :-
  maplist(length, L, Lengths),
  maxlist(Lengths, Max),
  minlist(Lengths, Min),
  Max == Min.

答案 1 :(得分:3)

@ Peteris的解决方案不必要地复杂。你可以这样做:

equal_lengths([]).
equal_lengths([[]]).
equal_lengths([[_|_]]).
equal_lengths([X,Y|Rest]) :- 
  length(X, Len), 
  length(Y, Len), 
  equal_lengths([Y|Rest]).

以归纳的方式思考。我断言空列表的长度和一个列表的列表是“相等的”(没有/只有一个可以比较)。然后我说如果第一个项目的长度等于第二个项目的长度,只要第二个项目的长度和其余的匹配我们就好了。

注意:我们没有明确说明X和Y的长度与某种相等测试相同。我们让Prolog通过简单地声明X和Y的长度是Len来处理它。因此,如果Y的长度不与X的长度统一,则谓词将失败。

撤消流程

因此,要编写一个谓词以确定是否所有列表都具有相同的长度,我们必须注意到,这次我们必须跟踪到目前为止已经看到的长度以进行检查。我们必须将每个列表的长度与所有先前列表长度进行比较,以确定不等式。所以这次我们的初始案例将创建长度的初始列表,并将处理推迟到另一个谓词:

unequal_lengths(X) :- unequal_lengths(X, []).

现在我们再次从类似的基本情况开始:

unequal_lengths([], _).
unequal_lengths([[]], _).
unequal_lengths([[_|_]], _).

当我们有一个实际的列表时,事情变得有趣:

unequal_lengths([X|Rest], Lengths) :-
  length(X, Len),
  \+ member(Len, Lengths),
  unequal_lengths(Rest, [Len|Lengths]).

所以我们计算这个列表的长度,然后断言这不是我们之前看到的方便成员谓词的长度,然后将这个长度和其余长度一起传递给列表的其余部分。

附录:不平等w / forall

受其他答案的启发,您可以按照更高阶的方式实现unequal_lengths:

unequal_lengths(Lists) :-
  findall(Len, (member(X, Lists), length(X, Len)), Lengths),
  forall(select(Len, Lengths, Remaining), \+ member(Len, Remaining)).

如果你考虑一下,这与问题的形式逻辑表达非常接近:对于每个列表长度,不存在与此对应的剩余列表长度的元素。

答案 2 :(得分:2)

我将使用SWI-Prolog builtins maplistaggregate重写Peteris的答案(+1):

equallists(L) :-
  maplist(length, L, Lengths),
  aggregate(max(T), member(T, Lengths), N),
  aggregate(min(T), member(T, Lengths), N).

完成!

更简单,使用lambda(此处为doc page)调整参数顺序:

:- [lambda].

equallists([H|T]) :-
  length(H, N),
  maplist(\L^length(L, N), T).

Variazione sul tema(这应该是最小的):

equallists([H|T]) :-
  length(H, N),
  forall(member(L, T), length(L, N)).

如@false所述,当T未接地时,测试可能会失败。可能的纠正:

equallists([H|T]) :-
  length(H, N),
  forall(member(L, T), (nonvar(L), length(L, N))).

forall / 2,我认为可以被描述为失败驱动循环的一种形式,很容易被误用。

OTOH,Prolog中的每个控制流构造都很难正确使用,这可能是该语言缺乏流行的主要原因。

答案 3 :(得分:2)

利用大多数Prolog系统中发现的第一个参数索引的解决方案,以避免在大多数(但不是全部)情况下出现假选择点:

E:\work\workspace\knowlege\play-scala-di>sbt
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
    java.lang.IllegalArgumentException: URI has an authority component
    at java.io.File.<init>(File.java:423)
    at sbt.Classpaths$.sbt$Classpaths$$bootRepository(Defaults.scala:1758)
    at sbt.Classpaths$$anonfun$appRepositories$1.apply(Defaults.scala:1729)
    at sbt.Classpaths$$anonfun$appRepositories$1.apply(Defaults.scala:1729)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
            at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
            at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
    at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:34)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
    at scala.collection.AbstractTraversable.map(Traversable.scala:105)
    at sbt.Classpaths$.appRepositories(Defaults.scala:1729)
    at sbt.Classpaths$$anonfun$41.apply(Defaults.scala:1102)
    at sbt.Classpaths$$anonfun$41.apply(Defaults.scala:1102)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.EvaluateSettings$MixedNode.evaluate0(INode.scala:175)
    at sbt.EvaluateSettings$INode.evaluate(INode.scala:135)
    at sbt.EvaluateSettings$$anonfun$sbt$EvaluateSettings$$submitEvaluate$1.apply$mcV$sp(INode.scala:69)
    at sbt.EvaluateSettings.sbt$EvaluateSettings$$run0(INode.scala:78)
    at sbt.EvaluateSettings$$anon$3.run(INode.scala:74)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    [error] java.lang.IllegalArgumentException: URI has an authority component

一些示例查询:

equal_lengths([]).
equal_lengths([L1| Ls]) :-
    equal_lengths_aux(Ls, L1).

equal_lengths_aux([], _).
equal_lengths_aux([L2| Ls], L1) :- 
    equal_length(L1, L2), 
    equal_lengths_aux(Ls, L2).

equal_length([], []).
equal_length([_| Tail1], [_| Tail2]) :-
    equal_length(Tail1, Tail2).

当第一个元素未绑定且存在绑定列表元素时,我们只会得到虚假选择点(即不会导致解决方案的选择点)。如果没有列表元素绑定到有限列表,谓词将生成列表长度不断增长的解决方案,如示例查询中所示。

答案 4 :(得分:2)

与第一次尝试相比,遵循第二种具有更好终止属性的解决方案。主要思想是每次遍历列表时,我们从每个列表中删除一个元素。

equal_lengths([]).
equal_lengths([L1| Ls]) :-
    pick(L1, Ls, Rs),
    equal_lengths(Rs).

pick([], Ls, []) :-
    all_empty(Ls).
pick([_| R1], Ls, [R1| Rs]) :-
    pick(Ls, Rs).

pick([], []).
pick([[_|R1]| Ls], Rs) :-
    pick([_|R1], Ls, Rs).

all_empty([]).
all_empty([[]| Rs]) :-
    all_empty(Rs).

我对第一个解决方案的评论中提到的有问题的案例@false是:

| ?- equal_lengths([_,_,[]]).

true ? ;

no

然而,更清楚的是,如果我们不使用匿名变量,我们会得到唯一正确的解决方案:

| ?- equal_lengths([L1,L2,[]]).

L1 = []
L2 = [] ? ;

no

我的第一个解决方案中的所有先前示例查询都没有问题。特别值得一提的是一个查询,因为它错误地只提供了一个解决方案,而不是在之前的尝试中生成解决方案。现在它按预期工作:

| ?- equal_lengths([L]).

L = [] ? ;

L = [_] ? ;

L = [_,_] ? ;

L = [_,_,_] ? ;

...

任何人都可以找到导致此解决方案出现问题的示例查询吗?

答案 5 :(得分:2)

菜单上的下一道菜:baroque 大杂烩。

$updatequality = $database->prepare("UPDATE products SET quantity=quantity - 1 AND purchases=purchases + 1 WHERE id=?");

一些示例查询:

?- Xss = [As,Bs,Cs], As=[], samelength_of(N,Xss).
N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = [].

?- Xss = [As,Bs,Cs], samelength_of(N,Xss), As=[].
N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = [].

更多?想试试比目鱼吗?

:- use_module(library(clpfd)).

samelength_of(N,Xss) :- maplist(length_of__lazy(N),Xss).

length_of__lazy(N,Xs) :-
   N #>= 0,
   (  nonvar(N)
   -> length(Xs,N)
   ;  var(Xs)
   -> when((nonvar(Xs);nonvar(N)), length_of__lazy(N,Xs))
   ;  Xs = []
   -> N = 0
   ;  Xs = [_|Xs0]
   -> N0 + 1 #= N,
      length_of__lazy(N0,Xs0)
   ;  throw(error(type_error(list,Xs),length_of__lazy/2))
   ).

my_indomain(N) :-
   fd_inf(N,I),
   (  N #= I
   ;  N #> I, my_indomain(N)
   ).
比目鱼不是你的口味吗? 没问题!

?- samelength_of(N,[As,Bs,Cs]).
N in 0..sup,
when((nonvar(As);nonvar(N)), length_of__lazy(N,As)),
when((nonvar(Bs);nonvar(N)), length_of__lazy(N,Bs)),
when((nonvar(Cs);nonvar(N)), length_of__lazy(N,Cs)).

答案 6 :(得分:1)

使用正确的工具--- maplist/2Prolog lambdas ---我们只需要一行:

?- Xss = [[1,2],[2,3],[3,4,5]], maplist(N+\Xs^length(Xs,N),Xss).
false.

?- Xss = [[1,2],[2,3],[3,4]],   maplist(N+\Xs^length(Xs,N),Xss).
N = 2.

(+\)/2帮助我们声明N是免费的,因此我们使用相同的N 作为Xs Xss的长度while (my_fgets(buf, sizeof(buf), f)) printf("%s\n", buf); 1}}。

答案 7 :(得分:-2)

我发现唯一可接受的解决方案是chac的最后一个,为了完整性我会添加空列表处理:

equalLengths([]).
equalLengths([Head|Tail]) :-
    length(Head, Length),
    forall(member(List, Tail), length(List, Length)).