Prolog - 将列表分为 N 部分

发布于 2024-12-24 03:01:49 字数 1646 浏览 1 评论 0原文

我正在尝试编写一个谓词,将列表分为 N 个部分。 这是我到目前为止所拥有的。

partition(1, List, List).
partition(N, List, [X,Y|Rest]):-
    chop(List, X, Y),
    member(NextToChop, [X,Y]), %Choose one of the new parts to chop further.
    NewN is N-1,
    partition(NewN, NextToChop, Rest).

chop(List, _, _):-
    length(List, Length),
    Length < 2, %You can't chop something that doesn't have at least 2 elements
    fail,!.
chop(List, Deel1, Deel2):-
    append(Deel1, Deel2, List),
    Deel1 \= [],
    Deel2 \= [].

这个想法是继续将列表的一部分分成另外两个部分,直到我有 N 部分。 我用这种方法得到了平庸的结果:

?- partition(2, [1,2,3,4], List).
List = [[1], [2, 3, 4], 1] ;
List = [[1], [2, 3, 4], 2, 3, 4] ;
List = [[1, 2], [3, 4], 1, 2] ;
List = [[1, 2], [3, 4], 3, 4] ;
List = [[1, 2, 3], [4], 1, 2, 3] ;
List = [[1, 2, 3], [4], 4] ;
false.

所以我得到了我想要的东西,但我得到了两次,并且还附加了一些其他东西。 当分成三部分时,情况会变得更糟:

?- partition(3, [1,2,3,4], List).
List = [[1], [2, 3, 4], [2], [3, 4], 2] ;
List = [[1], [2, 3, 4], [2], [3, 4], 3, 4] ;
List = [[1], [2, 3, 4], [2, 3], [4], 2, 3] ;
List = [[1], [2, 3, 4], [2, 3], [4], 4] ;
List = [[1, 2], [3, 4], [1], [2], 1] ;
List = [[1, 2], [3, 4], [1], [2], 2] ;
List = [[1, 2], [3, 4], [3], [4], 3] ;
List = [[1, 2], [3, 4], [3], [4], 4] ;
List = [[1, 2, 3], [4], [1], [2, 3], 1] ;
List = [[1, 2, 3], [4], [1], [2, 3], 2, 3] ;
List = [[1, 2, 3], [4], [1, 2], [3], 1, 2] ;
List = [[1, 2, 3], [4], [1, 2], [3], 3] ;
false.

另一个想法是使用前缀,但我不知道这会如何真正起作用。要使用它,我应该能够让 Prolog 知道它需要采用一个不太短也不太长的前缀,所以我不会采用太长的前缀,这样就没有什么可以留给下一个递归步骤了。

有人能指出我正确的方向吗?

需要澄清的是:谓词应该返回将列表分为 N 个部分的所有可能性(不包括空列表)。

I'm trying to write a predicate that divides a list into N parts.
This is what I have so far.

partition(1, List, List).
partition(N, List, [X,Y|Rest]):-
    chop(List, X, Y),
    member(NextToChop, [X,Y]), %Choose one of the new parts to chop further.
    NewN is N-1,
    partition(NewN, NextToChop, Rest).

chop(List, _, _):-
    length(List, Length),
    Length < 2, %You can't chop something that doesn't have at least 2 elements
    fail,!.
chop(List, Deel1, Deel2):-
    append(Deel1, Deel2, List),
    Deel1 \= [],
    Deel2 \= [].

The idea is to keep chopping parts of the list into two other parts until I have N pieces.
I have mediocre results with this approach:

?- partition(2, [1,2,3,4], List).
List = [[1], [2, 3, 4], 1] ;
List = [[1], [2, 3, 4], 2, 3, 4] ;
List = [[1, 2], [3, 4], 1, 2] ;
List = [[1, 2], [3, 4], 3, 4] ;
List = [[1, 2, 3], [4], 1, 2, 3] ;
List = [[1, 2, 3], [4], 4] ;
false.

So I get what I want, but I get it two times and there are some other things attached.
When dividing into 3 parts things get worse:

?- partition(3, [1,2,3,4], List).
List = [[1], [2, 3, 4], [2], [3, 4], 2] ;
List = [[1], [2, 3, 4], [2], [3, 4], 3, 4] ;
List = [[1], [2, 3, 4], [2, 3], [4], 2, 3] ;
List = [[1], [2, 3, 4], [2, 3], [4], 4] ;
List = [[1, 2], [3, 4], [1], [2], 1] ;
List = [[1, 2], [3, 4], [1], [2], 2] ;
List = [[1, 2], [3, 4], [3], [4], 3] ;
List = [[1, 2], [3, 4], [3], [4], 4] ;
List = [[1, 2, 3], [4], [1], [2, 3], 1] ;
List = [[1, 2, 3], [4], [1], [2, 3], 2, 3] ;
List = [[1, 2, 3], [4], [1, 2], [3], 1, 2] ;
List = [[1, 2, 3], [4], [1, 2], [3], 3] ;
false.

Another idea is using prefix but I don't know how that would really work. To use that I should be able to let Prolog know that it needs to take a prefix that's not too short and not too long either, so I don't take a prefix that's too long so there's nothing left for a next recursion step.

Can anyone point me in the right direction?

Little clarification: the predicate should return all posibilities of dividing the list in N parts (not including empty lists).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

掩于岁月 2024-12-31 03:01:49

当描述涉及列表的关系时,DCG 通常非常有用。考虑:

list_n_parts(List, N, Parts) :-
        length(Parts, N),
        phrase(parts(Parts), List).

parts([]) --> [].
parts([Part|Parts]) --> part(Part), parts(Parts).

part([P|Ps]) --> [P], list(Ps).

list([]) --> [].
list([L|Ls]) --> [L], list(Ls).

示例查询:

?- list_n_parts([1,2,3,4], 2, Ps).
Ps = [[1], [2, 3, 4]] ;
Ps = [[1, 2], [3, 4]] ;
Ps = [[1, 2, 3], [4]] ;
false.

When describing relations that involve lists, DCGs are often very useful. Consider:

list_n_parts(List, N, Parts) :-
        length(Parts, N),
        phrase(parts(Parts), List).

parts([]) --> [].
parts([Part|Parts]) --> part(Part), parts(Parts).

part([P|Ps]) --> [P], list(Ps).

list([]) --> [].
list([L|Ls]) --> [L], list(Ls).

Sample query:

?- list_n_parts([1,2,3,4], 2, Ps).
Ps = [[1], [2, 3, 4]] ;
Ps = [[1, 2], [3, 4]] ;
Ps = [[1, 2, 3], [4]] ;
false.
等数载,海棠开 2024-12-31 03:01:49

这是我用来实现该功能的基本方法(使用 append/2length/2):

list_n_parts(List, Parts, Result) :-
    length(Result, Parts),
    append(Result, List).

现在,这并不完全符合您的期望:它允许使用[]

解决这个问题的一个想法是使用 maplist 调用预先格式化结果列表:

list_n_parts(List, Parts, Result) :-
    length(Result, Parts),

使用 copy_term/2maplist/2 调用看起来就像:

    maplist(copy_term([_|_]), Result),

使用 functor/3 (归功于@false),它看起来像:

    maplist(functor('.', 2), Result),

使用 lambda.pl 你可以写:

    maplist(\[_|_]^true, Result),

因为 '\' 已经执行了术语复制(感谢@false)。

唯一剩下的是 append/2 调用:

    append(Result, List).

另一个想法是使用 forall/2 过滤(可能更容易获得,但复杂性更差):

list_n_parts(List, Parts, Result) :-
    length(Result, Parts),
    append(Result, List),
    forall(member(X, Result), X \= []).

等等。 。

Here is the basic way I'd use to implement that (using append/2 and length/2) :

list_n_parts(List, Parts, Result) :-
    length(Result, Parts),
    append(Result, List).

Now, that doesn't totally complies to your expectations : it allows for [].

One idea to fix that is to use a maplist call to format the Resulting list beforehand :

list_n_parts(List, Parts, Result) :-
    length(Result, Parts),

using copy_term/2, the maplist/2 call looks like :

    maplist(copy_term([_|_]), Result),

using functor/3 (credits to @false), it would look like :

    maplist(functor('.', 2), Result),

using lambda.pl you could write :

    maplist(\[_|_]^true, Result),

since the '\' already performs a term copy (thanks @false).

The only thing left is the append/2 call:

    append(Result, List).

Another idea would be to use forall/2 filtering (maybe simpler to get, but worse in complexity) :

list_n_parts(List, Parts, Result) :-
    length(Result, Parts),
    append(Result, List),
    forall(member(X, Result), X \= []).

etc...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文