将列表分解为连续子序列的列表

时间:2018-03-29 11:34:08

标签: list prolog

我真的很抱歉以前的问题,这是我第一次在这个网站上发帖提问,我真的不知道我不应该发布这样的问题。 这是我第一次使用prolog。实际上我在这个问题上花了5个多小时但仍然不能完全解决它,我试图将这个问题拆开,这里还有待解决的问题:

如何将连续增加的整数放入原始列表中的子列表中。

例如。 [3,5,1,2,3,7,8,2]至[3,5,[1,2,3],[7,8],2]

以下是我写的内容,有人可以告诉我如何修复代码吗?感谢。

{{1}}

enter image description here

4 个答案:

答案 0 :(得分:3)

感谢您更新问题以向我们展示您的尝试!

像所有Prolog初学者一样,你想要立刻做太多。这个是正常的!但是你必须学习并习惯一种与其他编程语言不同的思维方式。几乎总是你必须将你的问题分解成几个子问题,然后将它们放在一起以获得最终的程序。

因此,让我们首先尝试解决问题的一部分:给定一个非空列表,将其分解为前面的连续元素和所有剩余元素。也就是说,我们想要这样的东西:

?- list_successive_rest([1, 2, 4, 3], Succ, Rest).
Succ = [1, 2],
Rest = [4, 3] .

如果我们可以编写此定义,那么我们应该能够遍历Rest以进一步切割它。

以下是list_successive_rest/3的定义。请注意它是如何遵循chop_up/2尝试的结构,但它更短更简单,因为我们只查看列表的连续前缀,而不是一次查看所有列表:

list_successive_rest([X], [X], []).
list_successive_rest([A, B | Xs], [A], [B | Xs]) :-
    A + 1 =\= B.
list_successive_rest([A, B | Xs], [A | Successive], Rest) :-
    A + 1 =:= B,
    list_successive_rest([B | Xs], Successive, Rest).

(这也比你的版本简单,因为我将至少两个元素的列表与[A, B | Xs]而不是[A | Tail]Tail = [B | Tail2]匹配。习惯这种语法是个好主意。)

我们可以连续调用它来将列表分解为连续的部分:

?- list_successive_rest([1, 2, 4, 3], Succ, Rest), list_successive_rest(Rest, Succ2, Rest2), list_successive_rest(Rest2, Succ3, Rest3).
Succ = [1, 2],
Rest = [4, 3],
Succ2 = [4],
Rest2 = Succ3, Succ3 = [3],
Rest3 = [] ;
false.

使用上面的谓词迭代地剥离列表的连续前缀,现在可以很容易地定义chop_up/2

chop_up([], []).
chop_up(List, [Succ | Chopped]) :-
    list_successive_rest(List, Succ, Rest),
    chop_up(Rest, Chopped).

请注意chop_up/2是递归的,它使用list_successive_rest/3,它也是递归的。试图在一个递归谓词中写下所有这些内容会更难,导致代码可读性降低。

让我们尝试上面的测试和你的测试用例:

?- chop_up([1, 2, 4, 3], Chopped).
Chopped = [[1, 2], [4], [3]] ;
false.

?- chop_up([3,5,1,2,3,7,8,2], Chopped).
Chopped = [[3], [5], [1, 2, 3], [7, 8], [2]] ;
false.

这实际上并不会产生您想要的确切格式:Singleton元素是单例列表而不是外部列表的“裸”成员。我认为这种方式更好,但你的老师可能不同意。在这种情况下,更改这个小细节是一项练习。

答案 1 :(得分:3)

我用DCG提出了更优雅的方式!

chunk_list([])-->[].
chunk_list([C|Rest])-->chunk(C),chunk_list(Rest).

chunk(Ret)-->[First],consecutive(First,Last),{First=:=Last->Ret is First;Ret = [First,Last]}.

consecutive(Prev,Last)-->[Current],{Current is Prev+1},consecutive(Current,Last).
consecutive(Prev,Prev)-->[].

测试:

 ?- phrase(chunk_list(R),[1,2,3,6,7,3,3,2,3,4,6],[]).
R = [[1, 3], [6, 7], 3, 3, [2, 4], 6] 
也许它可以在更多的时候可以逆转。 I.E.将[[1,3],[6,7],3,3,[2,4],6]转换为[1,2,3,6,7,3,3,2,3,4,6]

答案 2 :(得分:1)

我也尝试过我的prolog培训。 可怕的计划,但无论如何确实有效。 我在ECLiPSe中对此进行了测试,但在其他环境中进行了少量修改(可能只是删除了:-lib(listut)

这样打电话:

chunk([4,5,6,3,4,4,57,3,4,5,7,2,3,4,5,7,7,54,3],Ret).

程序:

:-lib(listut).

chunk(List,Ans):-
    chunk_sub(List,0,[],List1),
    first_and_lasts(List1,Ans),
    !.


chunk_sub([],_,Ret,Reverse):-reverse(Ret,Reverse),!.
chunk_sub([Current|Rest],Prev,[NowList|RetRest],Ret):-
    Current =:= Prev+1,
    append(NowList,[Current],NextList),
    chunk_sub(Rest,Current,[NextList|RetRest],Ret).
chunk_sub([Current|Rest],_,NowList,Ret):-
    chunk_sub(Rest,Current,[[Current]|NowList],Ret).

first_and_lasts([],[]):-!.
first_and_lasts([FirstList|RestLists],[Converted|RestRet]):-
    length(FirstList,Len),
    (
        Len=:=1->
        ([OneElem]=FirstList,Converted=OneElem);
        (
            nth1(1,FirstList,Smallest),
            nth1(Len,FirstList,Biggest),
            Converted=[Smallest,Biggest]
        )
    ),
    first_and_lasts(RestLists,RestRet).

答案 3 :(得分:1)

最后我做到了! 这是可逆的(通用)版本。这个程序巧妙地工作。 发展这个非常有趣。

代码:

chunk_list([])-->[],!.
chunk_list([Chunk|Rest])-->chunk(Chunk),!,chunk_list(Rest).

chunk([First,Last])-->sequence([First,Last]),{First<Last}. % sequence
chunk(Val)-->sequence([Val,Val]).               % isolated number

sequence([First,Last])-->
                {(number(First),number(Last))->First<Last;true},
                [First],
                {succ(First,Second)},sequence([Second,Last]).
sequence([Val,Val])-->[Val].

测试:

[eclipse 4]: phrase(chunk_list([2,[2,6],[3,5],3,7,[1,3]]),Ret).

Ret = [2, 2, 3, 4, 5, 6, 3, 4, 5, 3, 7, 1, 2, 3]
Yes (0.00s cpu)

[eclipse 5]: phrase(chunk_list(Ret),[3,4,5,2,1,6,7,88,9,4,5,6,7,2,1,2,3]).

Ret = [[3, 5], 2, 1, [6, 7], 88, 9, [4, 7], 2, [1, 3]]
Yes (0.00s cpu)

[eclipse 6]: phrase(chunk_list([[2,4],A,[2,8],3]),[2,B,4,6,2,C,4,5,6,7,D,E]).

A = 6
B = 3
C = 3
D = 8
E = 3
Yes (0.00s cpu)