Prolog如何将列表列表添加到一个列表中?

时间:2022-02-08 07:12:34

So I'm totally new to Prolog and need some help. I'm trying to take a list of lists like [[1,2,3],[4,5,6],[7,8]] and create a list like [2,3,5,6,8], so basically all the values into a new list besides the first of each list. I got this:

所以我对Prolog很新,需要一些帮助。我正在尝试列出像[[1,2,3],[4,5,6],[7,8]]这样的列表,并创建一个像[2,3,5,6,8]这样的列表,所以除了每个列表的第一个之外,所有的值基本上都是新的列表。我懂了:

test5(X,[[_|X]|_]).
test5(X,[_|A]) :- test5(X,A).

which returns [2,3] and then [5,6] and then [8] each time I press enter. I'm not sure how to make them run all at once and make them into a list. I tried using append in different ways but I could not get this working. Any idea on how to implement this? Thanks!

每次按回车键,返回[2,3]然后[5,6]再然后[8]。我不确定如何让它们一次运行并将它们放入列表中。我尝试以不同的方式使用追加,但我无法使其工作。有关如何实现这一点的任何想法?谢谢!

2 个解决方案

#1


You have the common predicate flatten/2, which almost does the job:

你有共同的谓词flatten / 2,几乎完成了这项工作:

?- flatten([[1,2,3],[4,5,6],[7,8]], L).
L = [1, 2, 3, 4, 5, 6, 7, 8].

There are many implementations of flatten/2 available, just google it.

有很多flatten / 2可用的实现,只是google它。

If you know that the list of lists is not nested, you should rather use append/2.

如果您知道列表列表未嵌套,则应使用append / 2。

Then, you need to drop the first element of each list before appending:

然后,您需要在追加之前删除每个列表的第一个元素:

list_tail([_|T], T).

Then:

?- maplist(list_tail, [[1,2,3],[4,5,6],[7,8]], T), append(T, L).
T = [[2, 3], [5, 6], [8]],
L = [2, 3, 5, 6, 8].

It might be a good exercise to take a more careful look at the implementation of append/2 linked above. With a small change in the definition (literally removing 1 character and adding 5) it will do the dropping and appending in the same step, without traversing the original list twice.

仔细研究上面链接的append / 2的实现可能是一个很好的练习。通过定义中的小变化(逐字地删除1个字符并添加5),它将执行删除并在同一步骤中追加,而不会遍历原始列表两次。

EDIT

So why is it that @repeat's initial solution does not terminate when the first argument is not a proper list, but the second is a proper list?

那么,为什么@ repeat的初始解决方案不会在第一个参数不是正确的列表时终止,但第二个是正确的列表?

nt_tails_append([[_|T]|Ls], As) :-
    append(T, Ws, As),
    nt_tails_append(Ls, Ws).

It is because when the first argument to nt_tails_append/2 is a free variable, the first two arguments to append/3 above are variables, too. When we call append/3 in this mode, we get, by definition:

这是因为当nt_tails_append / 2的第一个参数是一个*变量时,上面追加/ 3的前两个参数也是变量。当我们在这种模式下调用append / 3时,根据定义我们得到:

?- append(A, B, L).
A = [],
B = L .

In other words, the second and the third arguments are now unified. With the definition of nt_tail_append/2, this means that the recursive call gets the same second argument as the original call, and a new free variable as the first argument. This is an endless loop, of course.

换句话说,第二个和第三个参数现在是统一的。通过定义nt_tail_append / 2,这意味着递归调用获得与原始调用相同的第二个参数,并将新的*变量作为第一个参数。当然,这是一个无限循环。

(Tellingly, if you care to look at the definition of append/2 linked above, you will see that the first argument must_be a list.)

(引人注目的是,如果你想看看上面链接的append / 2的定义,你会看到第一个参数must_be是一个列表。)

How does this help?

这有什么用?

tails_append(Ls, As) :-
    maplist(list_tail, Ls, T),
    append(T, As).

list_tail([_|T], T).

The way that maplist is defined, all list arguments will be instantiated to proper lists. So you can safely use append/3 (here, used in the definition of append/2).

定义maplist的方式,所有列表参数都将实例化为正确的列表。所以你可以安全地使用append / 3(这里,在append / 2的定义中使用)。

#2


Here is how you could do it using append/3:

以下是使用append / 3的方法:

lists_concatenatedTails([],[]).
lists_concatenatedTails([[_|Xs0]|Xss],Ys) :-
    append(Xs0,Ys0,Ys),
    lists_concatenatedTails(Xss,Ys0).

Sample query:

?- lists_concatenatedTails([[1,2,3],[4,5,6],[7,8]], Xs).
Xs = [2, 3, 5, 6, 8].

Edit 2015-05-07

Note that the code that @Boris suggested (using list_tail/2,maplist/3,append/2) also gives answers for the following query:

请注意,@ Boris建议的代码(使用list_tail / 2,maplist / 3,append / 2)也为以下查询提供了答案:

?- maplist(list_tail,Xss,Yss), append(Yss,[1,2,3]).
Xss = [[_G97, 1, 2, 3]],                   Yss = [[1, 2, 3]]         ;
Xss = [[_G97], [_G106, 1, 2, 3]],          Yss = [[], [1, 2, 3]]     ;
Xss = [[_G97, 1], [_G106, 2, 3]],          Yss = [[1], [2, 3]]       ;
Xss = [[_G97, 1, 2], [_G106, 3]],          Yss = [[1, 2], [3]]       ;
Xss = [[_G97, 1, 2, 3], [_G106]],          Yss = [[1, 2, 3], []]     ;
Xss = [[_G97], [_G106], [_G115, 1, 2, 3]], Yss = [[], [], [1, 2, 3]] ...

This doesn't terminate universally---nor do we expect it to: the set of solutions is infinite in size and it can, in this case, only be covered by an infinite sequence of answers.

这并不是普遍终止的 - 我们也不期望它:解决方案集的大小是无限的,在这种情况下,它只能被无限的答案序列所覆盖。

In the following equivalent query lists_concatenatedTails/2 "loops" right away:

在以下等效查询中,lists_concatenatedTails / 2“循环”立即:

?- lists_concatenatedTails(Lss,[1,2,3]).
% not a single answer within finite time

Only when constraining the length of Lss right away, fair enumeration can be achieved:

只有在立即限制Lss的长度时,才能实现公平的枚举:

?- length(Lss,_), lists_concatenatedTails(Lss,[1,2,3]).
Lss = [[_G23, 1, 2, 3]] ;
Lss = [[_G26], [_G29, 1, 2, 3]] ;
Lss = [[_G26, 1], [_G32, 2, 3]] ;
Lss = [[_G26, 1, 2], [_G35, 3]] ;
Lss = [[_G26, 1, 2, 3], [_G38]] ;
Lss = [[_G29], [_G32], [_G35, 1, 2, 3]] ...

#1


You have the common predicate flatten/2, which almost does the job:

你有共同的谓词flatten / 2,几乎完成了这项工作:

?- flatten([[1,2,3],[4,5,6],[7,8]], L).
L = [1, 2, 3, 4, 5, 6, 7, 8].

There are many implementations of flatten/2 available, just google it.

有很多flatten / 2可用的实现,只是google它。

If you know that the list of lists is not nested, you should rather use append/2.

如果您知道列表列表未嵌套,则应使用append / 2。

Then, you need to drop the first element of each list before appending:

然后,您需要在追加之前删除每个列表的第一个元素:

list_tail([_|T], T).

Then:

?- maplist(list_tail, [[1,2,3],[4,5,6],[7,8]], T), append(T, L).
T = [[2, 3], [5, 6], [8]],
L = [2, 3, 5, 6, 8].

It might be a good exercise to take a more careful look at the implementation of append/2 linked above. With a small change in the definition (literally removing 1 character and adding 5) it will do the dropping and appending in the same step, without traversing the original list twice.

仔细研究上面链接的append / 2的实现可能是一个很好的练习。通过定义中的小变化(逐字地删除1个字符并添加5),它将执行删除并在同一步骤中追加,而不会遍历原始列表两次。

EDIT

So why is it that @repeat's initial solution does not terminate when the first argument is not a proper list, but the second is a proper list?

那么,为什么@ repeat的初始解决方案不会在第一个参数不是正确的列表时终止,但第二个是正确的列表?

nt_tails_append([[_|T]|Ls], As) :-
    append(T, Ws, As),
    nt_tails_append(Ls, Ws).

It is because when the first argument to nt_tails_append/2 is a free variable, the first two arguments to append/3 above are variables, too. When we call append/3 in this mode, we get, by definition:

这是因为当nt_tails_append / 2的第一个参数是一个*变量时,上面追加/ 3的前两个参数也是变量。当我们在这种模式下调用append / 3时,根据定义我们得到:

?- append(A, B, L).
A = [],
B = L .

In other words, the second and the third arguments are now unified. With the definition of nt_tail_append/2, this means that the recursive call gets the same second argument as the original call, and a new free variable as the first argument. This is an endless loop, of course.

换句话说,第二个和第三个参数现在是统一的。通过定义nt_tail_append / 2,这意味着递归调用获得与原始调用相同的第二个参数,并将新的*变量作为第一个参数。当然,这是一个无限循环。

(Tellingly, if you care to look at the definition of append/2 linked above, you will see that the first argument must_be a list.)

(引人注目的是,如果你想看看上面链接的append / 2的定义,你会看到第一个参数must_be是一个列表。)

How does this help?

这有什么用?

tails_append(Ls, As) :-
    maplist(list_tail, Ls, T),
    append(T, As).

list_tail([_|T], T).

The way that maplist is defined, all list arguments will be instantiated to proper lists. So you can safely use append/3 (here, used in the definition of append/2).

定义maplist的方式,所有列表参数都将实例化为正确的列表。所以你可以安全地使用append / 3(这里,在append / 2的定义中使用)。

#2


Here is how you could do it using append/3:

以下是使用append / 3的方法:

lists_concatenatedTails([],[]).
lists_concatenatedTails([[_|Xs0]|Xss],Ys) :-
    append(Xs0,Ys0,Ys),
    lists_concatenatedTails(Xss,Ys0).

Sample query:

?- lists_concatenatedTails([[1,2,3],[4,5,6],[7,8]], Xs).
Xs = [2, 3, 5, 6, 8].

Edit 2015-05-07

Note that the code that @Boris suggested (using list_tail/2,maplist/3,append/2) also gives answers for the following query:

请注意,@ Boris建议的代码(使用list_tail / 2,maplist / 3,append / 2)也为以下查询提供了答案:

?- maplist(list_tail,Xss,Yss), append(Yss,[1,2,3]).
Xss = [[_G97, 1, 2, 3]],                   Yss = [[1, 2, 3]]         ;
Xss = [[_G97], [_G106, 1, 2, 3]],          Yss = [[], [1, 2, 3]]     ;
Xss = [[_G97, 1], [_G106, 2, 3]],          Yss = [[1], [2, 3]]       ;
Xss = [[_G97, 1, 2], [_G106, 3]],          Yss = [[1, 2], [3]]       ;
Xss = [[_G97, 1, 2, 3], [_G106]],          Yss = [[1, 2, 3], []]     ;
Xss = [[_G97], [_G106], [_G115, 1, 2, 3]], Yss = [[], [], [1, 2, 3]] ...

This doesn't terminate universally---nor do we expect it to: the set of solutions is infinite in size and it can, in this case, only be covered by an infinite sequence of answers.

这并不是普遍终止的 - 我们也不期望它:解决方案集的大小是无限的,在这种情况下,它只能被无限的答案序列所覆盖。

In the following equivalent query lists_concatenatedTails/2 "loops" right away:

在以下等效查询中,lists_concatenatedTails / 2“循环”立即:

?- lists_concatenatedTails(Lss,[1,2,3]).
% not a single answer within finite time

Only when constraining the length of Lss right away, fair enumeration can be achieved:

只有在立即限制Lss的长度时,才能实现公平的枚举:

?- length(Lss,_), lists_concatenatedTails(Lss,[1,2,3]).
Lss = [[_G23, 1, 2, 3]] ;
Lss = [[_G26], [_G29, 1, 2, 3]] ;
Lss = [[_G26, 1], [_G32, 2, 3]] ;
Lss = [[_G26, 1, 2], [_G35, 3]] ;
Lss = [[_G26, 1, 2, 3], [_G38]] ;
Lss = [[_G29], [_G32], [_G35, 1, 2, 3]] ...