我找到了一个非常好的Erlang实现,用于按位置对列表成员进行分组。
everynth(List, N) ->
[ lists:reverse(Y)
|| Y <- lists:foldl(
fun(X, [H|T]) -> T++[[X|H]] end,
lists:duplicate(N, []),
List)
].
这会将提供的列表(List)按其索引位置分为3组:
everynth([1, 2, 3, 4, 5, 6, 7, 8, 9], 3).
给出
[[1,4,7],[2,5,8],[3,6,9]].
我想在Prolog中做同样的事,但我不知道该怎么做。你能帮助我吗?谢谢。
答案 0 :(得分:1)
我们可以在Prolog中以与Erlang版本非常接近的方式实现它。
例如,使用Ulrich Neumerkel的library(lambda)
:
everynth(Ls, N, Groups) :- findall([], between(1,N,_), Groups0), foldl(\L^[G0|Gs0]^Gs^append(Gs0,[[L|G0]],Gs), Ls, Groups0, Groups1), maplist(reverse, Groups1, Groups).
根据您的Prolog系统,您可能需要导入一个或两个库来运行它。
在其他相似之处中,这带来了一个非常不幸的缺点。 练习:哪个?提示:Imeanapartfromthename。
为克服上述缺点,我还展示了替代解决方案。
我将使用的关键构建块是with_remainder_mod/5
,定义为:
with_remainder_mod(N, L, R-L, I0, I) :- R #= I0 mod N, I #= I0 + 1.
从本质上讲,这为每个元素配备了 index (mod N
)的残留。例如:
?- foldl(with_remainder_mod(3), [a,b,c,d,e,f], Rs, 0, _). Rs = [0-a, 1-b, 2-c, 0-d, 1-e, 2-f].
我们几乎已完成,因为我们现在可以使用ISO标准谓词keysort/2
,然后使用广泛可用的group_pairs_by_key/2
或类似的库谓词:
?- foldl(with_remainder_mod(3), [a,b,c,d,e,f], Rs0, 0, _), keysort(Rs0, Rs), group_pairs_by_key(Rs, Gs). Rs0 = [0-a, 1-b, 2-c, 0-d, 1-e, 2-f], Rs = [0-a, 0-d, 1-b, 1-e, 2-c, 2-f], Gs = [0-[a, d], 1-[b, e], 2-[c, f]].
总的来说,完整的解决方案可能如下所示:
with_remainder_mod(N, L, R-L, I0, I) :- R #= I0 mod N, I #= I0 + 1. every_nth(Ls0, N, Groups) :- foldl(with_remainder_mod(N), Ls0, Rs0, 0, _), keysort(Rs0, Rs), group_pairs_by_key(Rs, KeyGroups), pairs_values(KeyGroups, Groups).
时间复杂度为Θ(n·log n),其中 n 是列表的长度。
请注意,此解决方案使用:
foldl/5
这是一个非常有用的meta-predicate,已经附带了多个Prolog系统。同样,根据您的Prolog系统,您可能需要导入一个或两个库以使用这些工具和其他谓词,如pairs_values/2
或等效的。{/ p>
您的示例查询和答案:
?- every_nth([1,2,3,4,5,6,7,8,9], 3, Ls). Ls = [[1, 4, 7], [2, 5, 8], [3, 6, 9]].
当然,更多一般性查询也是可能的:
?- length(Es, _), every_nth(Es, 3, Ls). Es = Ls, Ls = [] ; Es = [X1], Ls = [[X1]] ; Es = [X1, X2], Ls = [[X1], [X2]] ; Es = [X1, X2, X3], Ls = [[X1], [X2], [X3]] ; Es = [X1, X2, X3, X4], Ls = [[X1, X4], [X2], [X3]] ; Es = [X1, X2, X3, X4, X5], Ls = [[X1, X4], [X2, X5], [X3]] ; etc.
请注意,基于findall/3
的版本无法执行此操作,因为findall/3
会创建新的副本变量。
以下是基准,可能对您在不同解决方案之间做出决定非常有用:
?- length(_, E), portray_clause(2^E), N #= 2^E, I #= N // 2, length(Ls, N), time(every_nth(Ls,I,_)), false. 2^0. % 150 inferences, 0.000 CPU in 0.000 seconds (80% CPU, 4545455 Lips) 2^1. % 34 inferences, 0.000 CPU in 0.000 seconds (78% CPU, 2428571 Lips) 2^2. % 62 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 4428571 Lips) 2^3. % 118 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 6555556 Lips) 2^4. % 230 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 8214286 Lips) 2^5. % 454 inferences, 0.000 CPU in 0.000 seconds (94% CPU, 9659574 Lips) 2^6. % 902 inferences, 0.000 CPU in 0.000 seconds (96% CPU, 10488372 Lips) 2^7. % 1,798 inferences, 0.000 CPU in 0.000 seconds (92% CPU, 9364583 Lips) 2^8. % 3,590 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 10316092 Lips) 2^9. % 7,174 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 11297638 Lips) 2^10. % 14,342 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 10491587 Lips) etc.
答案 1 :(得分:0)
不是很优雅,但应该有用。
getEveryNth([], _, [], _).
getEveryNth([H|Ti], N, [H|To], N) :-
getEveryNth(Ti, 1, To, N).
getEveryNth([_|Ti], M, Lo, N) :-
M < N,
Mp1 is M+1,
getEveryNth(Ti, Mp1, Lo, N).
everyNthH(_, 0, [], _).
everyNthH([H|Ti], M, [[H|To] | Lo], N) :-
M > 0,
Mm1 is M-1,
getEveryNth(Ti, 1, To, N),
everyNthH(Ti, Mm1, Lo, N).
everyNth(L, N, LL) :-
everyNthH(L, N, LL, N).
来自
everyNth([1, 2, 3, 4, 5, 6, 7, 8, 9], 3, L)
我得到(L
统一)
[[1,4,7],[2,5,8],[3,6,9]]
答案 2 :(得分:0)
我不得不做一些尝试&amp;测试找到索引之间的正确关系,你可以从变量&#39; everynth_starting / 4的名称已经未列入&#39;轻松调试。
everynth(L, P, Gs) :-
findall(G, (
between(1, P, S),
everynth_starting(L, P, S, G)
), Gs).
everynth_starting(L, P, S, G) :-
findall(E, (nth1(I, L, E), S mod P=:=I mod P), G).
nth1 / 3充当对索引/元素
的生成器