在 Prolog 中动态拆分列表
Split a list dynamically in Prolog
几周前我开始使用序言,但我看到了更深入的操作列表的递归谓词的构造。我的问题是:是否可以构建一个谓词,将给定列表拆分为给定数量的其他列表?
比如我想象的:
split([H|T], NumberLists, Lists)
-- 递归实现 --
?- split([1,2,3,4,5,6,7,8],2,Lists).
Lists = [[1,2,3,4],[5,6,7,8]].
?- split([1,2,3,4,5,6,7,8],4,Lists).
Lists = [[1,2],[3,4],[5,6],[7,8]].
谁能给我一个实现的例子?
谢谢!
:- use_module(library(clpfd)).
:- use_module(library(lambda)).
我们这样定义split/3
:
split(Xs,N,Yss) :-
length(Xs,L),
N #=< L,
[L0,L1] ins 1..sup,
L0 #= L / N,
L1 #= L - L0*(N-1),
% enumerate `N` *now* if domain is finite.
% ideally, length/2 does something like this (by itself).
( fd_size(N,Size),integer(Size) -> indomain(N) ; true ),
length(Yss,N),
append(Yss0,[Ys],Yss), % creates useless choicepoint
maplist(\Ls^length(Ls,L0),Yss0),
length(Ys,L1),
append(Yss,Xs). % note we use append/2 here, not append/3
首先,OP 给出的查询:
?- split([1,2,3,4,5,6,7,8],2,Lists).
Lists = [[1,2,3,4], [5,6,7,8]]
; false.
?- split([1,2,3,4,5,6,7,8],4,Lists).
Lists = [[1,2], [3,4], [5,6], [7,8]]
; false.
然后,一个更一般的例子:
?- split([1,2,3,4,5,6,7,8],N,Lss).
N = 1, Lss = [[1,2,3,4,5,6,7,8]]
; N = 2, Lss = [[1,2,3,4], [5,6,7,8]]
; N = 3, Lss = [[1,2], [3,4], [5,6,7,8]]
; N = 4, Lss = [[1,2], [3,4], [5,6], [7,8]]
; N = 5, Lss = [[1], [2], [3], [4], [5,6,7,8]]
; N = 6, Lss = [[1], [2], [3], [4], [5], [6,7,8]]
; N = 7, Lss = [[1], [2], [3], [4], [5], [6], [7,8]]
; N = 8, Lss = [[1], [2], [3], [4], [5], [6], [7], [8]]
; false.
您显示的示例(所有相同长度的列表)可以覆盖
split(L, N, S) :-
length_list(N, S),
append(S, L),
maplist(length_list(_), S).
length_list(Length, List) :- length(List, Length).
应该做这样的事情。没有内置谓词:
partition( [] , _ , [] ) . % the empty list is already partitioned
partition( Xs , N , [Pfx|Ys] ) :- % for a non-empty list, we...
take(N,Xs, Pfx , Sfx ) , % - split it into a prefix of (at most) length N and its suffix.
partition(Sfx,N,Ys) % - recursively partition the suffix
. % Easy!
take( 0 , Xs , [] , Xs ) . % if we reach zero, we're done. Close the prefix and hand back whatever is left over.
take( N , [] , [] , [] ) :- % if we exhaust the source list, we're done. close the prefix and hand back the empty list as the suffix.
N > 0 % - assuming, of course, that N is greater than zero.
. %
take( N , [X|Xs] , [X|Ys] , Sfx ) :- % otherwise prepend the current item to the prefix
N > 0 , % - assuming N is greater than zero,
N1 is N-1 , % - then decrement N
take(N1,Xs,Ys,Sfx) % - and recurse down.
. % Also easy!
几周前我开始使用序言,但我看到了更深入的操作列表的递归谓词的构造。我的问题是:是否可以构建一个谓词,将给定列表拆分为给定数量的其他列表?
比如我想象的:
split([H|T], NumberLists, Lists)
-- 递归实现 --
?- split([1,2,3,4,5,6,7,8],2,Lists).
Lists = [[1,2,3,4],[5,6,7,8]].
?- split([1,2,3,4,5,6,7,8],4,Lists).
Lists = [[1,2],[3,4],[5,6],[7,8]].
谁能给我一个实现的例子?
谢谢!
:- use_module(library(clpfd)).
:- use_module(library(lambda)).
我们这样定义split/3
:
split(Xs,N,Yss) :-
length(Xs,L),
N #=< L,
[L0,L1] ins 1..sup,
L0 #= L / N,
L1 #= L - L0*(N-1),
% enumerate `N` *now* if domain is finite.
% ideally, length/2 does something like this (by itself).
( fd_size(N,Size),integer(Size) -> indomain(N) ; true ),
length(Yss,N),
append(Yss0,[Ys],Yss), % creates useless choicepoint
maplist(\Ls^length(Ls,L0),Yss0),
length(Ys,L1),
append(Yss,Xs). % note we use append/2 here, not append/3
首先,OP 给出的查询:
?- split([1,2,3,4,5,6,7,8],2,Lists).
Lists = [[1,2,3,4], [5,6,7,8]]
; false.
?- split([1,2,3,4,5,6,7,8],4,Lists).
Lists = [[1,2], [3,4], [5,6], [7,8]]
; false.
然后,一个更一般的例子:
?- split([1,2,3,4,5,6,7,8],N,Lss).
N = 1, Lss = [[1,2,3,4,5,6,7,8]]
; N = 2, Lss = [[1,2,3,4], [5,6,7,8]]
; N = 3, Lss = [[1,2], [3,4], [5,6,7,8]]
; N = 4, Lss = [[1,2], [3,4], [5,6], [7,8]]
; N = 5, Lss = [[1], [2], [3], [4], [5,6,7,8]]
; N = 6, Lss = [[1], [2], [3], [4], [5], [6,7,8]]
; N = 7, Lss = [[1], [2], [3], [4], [5], [6], [7,8]]
; N = 8, Lss = [[1], [2], [3], [4], [5], [6], [7], [8]]
; false.
您显示的示例(所有相同长度的列表)可以覆盖
split(L, N, S) :-
length_list(N, S),
append(S, L),
maplist(length_list(_), S).
length_list(Length, List) :- length(List, Length).
应该做这样的事情。没有内置谓词:
partition( [] , _ , [] ) . % the empty list is already partitioned
partition( Xs , N , [Pfx|Ys] ) :- % for a non-empty list, we...
take(N,Xs, Pfx , Sfx ) , % - split it into a prefix of (at most) length N and its suffix.
partition(Sfx,N,Ys) % - recursively partition the suffix
. % Easy!
take( 0 , Xs , [] , Xs ) . % if we reach zero, we're done. Close the prefix and hand back whatever is left over.
take( N , [] , [] , [] ) :- % if we exhaust the source list, we're done. close the prefix and hand back the empty list as the suffix.
N > 0 % - assuming, of course, that N is greater than zero.
. %
take( N , [X|Xs] , [X|Ys] , Sfx ) :- % otherwise prepend the current item to the prefix
N > 0 , % - assuming N is greater than zero,
N1 is N-1 , % - then decrement N
take(N1,Xs,Ys,Sfx) % - and recurse down.
. % Also easy!