Prolog - 如何从平面列表中创建具有一定长度的列表

时间:2017-10-07 12:45:38

标签: list prolog chunking

例如:

createlistoflists([1,2,3,4,5,6,7,8,9], NewLists)
NewLists = [[1,2,3], [4,5,6], [7,8,9].

所以基本上我的第一个参数是一个列表,我的第二个参数是一个新列表,其中包含具有适当长度的列表(适当的长度为3)。我的第一个想法是使用某种附加物。但我真的不知道怎么做,有什么想法吗?

提前致谢

1 个答案:

答案 0 :(得分:4)

如果你不介意使用Prolog为你提供的漂亮设施,那就有一个简单的方法;

list_length(Size, List) :- length(List, Size).

split_list(List, SubSize, SubLists) :-
    maplist(list_length(SubSize), SubLists),
    append(SubLists, List).

您可以将其查询为:

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

如果List以长度不是SubSize的倍数的方式实例化,则会失败。

<小时/> 正如Will Ness在评论中所指出的,上述简单解决方案存在一个缺陷:maplist(list_length(SubSize), SubList)将继续查询并查找更长和更长的子列表集,不受约束。因此,在重试时,上面的查询不会终止。

诱惑就是使用这样的剪辑:

split_list(List, SubSize, SubLists) :-
    maplist(list_length(SubSize), SubLists), !,
    append(SubLists, List).

这里的剪辑假设您只想获得一个答案,就好像您正在编写命令功能一样。

更好的方法是尝试以合理的方式将SubList参数约束到maplist。一个简单的方法是确保SubList的长度不超过List的长度,因为从逻辑上讲,它应该永远不会更大。添加此约束:

list_length(Size, List) :- length(List, Size).

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

split_list(List, SubSize, SubLists) :-
    not_longer_than(SubLists, List),
    maplist(list_length(SubSize), SubLists),
    append(SubLists, List).

然后查询终止而不会失去解决方案的一般性:

?- split_list([1,2,3,4,5,6,7,8,9], 3, L).
L = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ;
false.

?-

not_longer_than/2的实施中,可以更准确地使用SubSize作为倍数。这样会更有效但不需要终止。

not_longer_than_multiple(L1, Mult, L2) :-
    not_longer_than_multiple(L1, Mult, Mult, L2).

not_longer_than_multiple([], _, _, []).
not_longer_than_multiple([], _, _, [_|_]).
not_longer_than_multiple([_|Xs], Mult, 1, [_|Ys]) :-
    not_longer_than_multiple(Xs, Mult, Mult, Ys).
not_longer_than_multiple(Xs, Mult, C, [_|Ys]) :-
    C #> 1,
    C1 #= C - 1,
    not_longer_than_multiple(Xs, Mult, C1, Ys).

或者沿着那些方向......

<小时/> 但是,如果我们要经历所有那些无意义的事情来掩盖maplist这种使用的罪行,那么正面碰到这个问题就可以得到最清晰的解决方案:

split_list(List, SubSize, SubLists) :-
    split_list(List, SubSize, SubSize, SubLists).

split_list([], _, _, []).
split_list([X|Xs], SubList, 1, [[X]|S]) :-
    split_list(Xs, SubList, SubList, S).
split_list([X|Xs], SubSize, C, [[X|T]|S]) :-
    C #> 1,
    C1 #= C - 1,
    split_list(Xs, SubSize, C1, [T|S]).