【问题标题】:How to take the head of one list in a list of lists and put it in another list?如何在列表列表中获取一个列表的头部并将其放入另一个列表中?
【发布时间】:2014-01-30 21:19:57
【问题描述】:

我有一个列表,看起来像这样:

[[b,c],[],[a]]

我想编写一个谓词,它将从一个列表的顶部获取一个特定的字母,并将其放入另一个列表中。要移动的字母是预先指定的。它可以放在一个空列表的顶部,或者包含一个更大的字母(b 可以放在 c 上,但不能放在其他地方)。该字母应在移动后从原始列表中删除。

我无法告诉 Prolog 查找以指定字母开头的列表,以及如何告诉 Prolog 将其放入另一个列表中。

【问题讨论】:

    标签: prolog


    【解决方案1】:

    这是我的解决方案,基于没有 [nth1][1]/4(好吧,你应该阅读 nth0/4 的文档,真的)

    /* takes a specific letter from the top of one of the lists, and puts it in another list.
       The letter to be moved is specified beforehand.
       It can be placed on top of a list which is either empty, or contains a letter that is larger (b can be placed on c, but not otherwise).
       The letter should be removed from the original list after it has been moved.
    */
    
    move_letter(Letter, Lists, Result) :-
        % search Letter, Temp0 miss amended list [Letter|Rest]
        nth1(I, Lists, [Letter|Rest], Temp0),
        % reinsert Rest, Temp1 just miss Letter
        nth1(I, Temp1, Rest, Temp0),
        % search an appropriate place to insert Letter
        nth1(J, Temp1, Candidate, Temp2),
        % insertion constraints
        J \= I, (Candidate = [] ; Candidate = [C|_], C @> Letter),
        % update Result
        nth1(J, Result, [Letter|Candidate], Temp2).
    

    用法示例:

    ?- move_letter(a,[[b,c],[],[a]],R).
    R = [[a, b, c], [], []] ;
    R = [[b, c], [a], []] ;
    false.
    
    ?- move_letter(b,[[b,c],[],[a]],R).
    R = [[c], [b], [a]] ;
    false.
    

    我遵循这种“非惯用”的方法来简化检查插入发生在与删除不同的位置。

    【讨论】:

    • nth0/3-4nth1/3-4 通常是 library 谓词,而不是 内置 谓词。对于未指定特定 Prolog 实现的问题,最好始终添加关于使用非标准(官方或事实上的)谓词的注释。
    • 谢谢@PauloMoura。你是对的,当然。前段时间还有一个关于实现nth1/4的问题,我answered
    【解决方案2】:

    以下是查找以某个元素开头的列表的一些规则。

    starts_with([H|T], H). 
    find_starts_with([],C,[]).
    find_starts_with([H|T],C,[H|Y]) :- starts_with(H,C),find_starts_with(T,C,Y).
    find_starts_with([H|T],C,L) :- \+ starts_with(H,C), find_starts_with(T,C,L).
    

    例子:

    | ?- find_starts_with([[1,2],[3,4],[1,5]],1,X).
    
    X = [[1,2],[1,5]] ? ;
    

    【讨论】:

    • 谢谢!这已经朝着好的方向迈出了一步,但是您如何建议我删除该列表的顶部并将其放在另一个为空或包含较大字母的列表的顶部?
    • 你能提供一个输入/输出方面的例子吗?
    • 输入可以是 (b, [[b,c],[],[a]], X),输出应该是 X = [[c],[b],[a]]
    【解决方案3】:

    我喜欢@CapelliC 简洁的解决方案。这是一个不使用 nth1 内置的替代解决方案。为糟糕的变量名称道歉。

    % move_letter : Result is L with the letter C removed from the beginning
    % of one sublist and re-inserted at the beginning of another sublist
    % such that the new letter is less than the original beginning letter
    % of that sublist
    %
    move_letter(C, L, Result) :-
        removed_letter(C, L, R, N),        % Find & remove letter from a sublist
        insert_letter(C, R, 0, N, Result). % Result is R with the letter inserted
    
    % removed_letter : R is L with the letter C removed from the beginning of a
    % sublist. The value N is the position within L that the sublist occurs 
    %
    removed_letter(C, L, R, N) :-
        removed_letter(C, L, R, 0, N).
    removed_letter(C, [[C|T]|TT], [T|TT], A, A).
    removed_letter(C, [L|TT], [L|TTR], A, N) :-
        A1 is A + 1,
        removed_letter(C, TT, TTR, A1, N).
    
    % Insert letter in empty sublist if it's not where the letter came from;
    % Insert letter at front of a sublist if it's not where the letter came from
    % and the new letter is less than the current head letter;
    % Or insert letter someplace later in the list of sublists
    %
    insert_letter(C, [[]|TT], A, N, [[C]|TT]) :-
        A \== N.
    insert_letter(C, [[C1|T]|TT], A, N, [[C,C1|T]|TT]) :-
        A \== N,
        C @< C1.
    insert_letter(C, [L|TT], A, N, [L|TTR]) :-
        A1 is A + 1,
        insert_letter(C, TT, A1, N, TTR).
    

    结果:

    | ?- move_letter(a, [[b,c],[],[a]], R).
    
    R = [[a,b,c],[],[]] ? a
    
    R = [[b,c],[a],[]]
    
    no
    
    | ?- move_letter(b, [[b,c],[],[a]], R).
    
    R = [[c],[b],[a]] ? a
    
    no
    
    | ?- move_letter(b, [[b,c], [], [a], [b,d]], R).
    
    R = [[c],[b],[a],[b,d]] ? a
    
    R = [[b,c],[b],[a],[d]]
    
    no
    

    【讨论】:

    • 也是非常棒的贡献!我认为尽可能避免使用内置谓词是件好事。谢谢。
    • @Boreq 谢谢。从技术上讲,像is/2 这样的谓词是一个内置谓词,所以这个解决方案并不能完全避免内置谓词。但它确实坚持 ISO 结构,并且适用于大多数 Prolog 解释器。看到不同的解决方案的好处是在每种情况下都有一些关于 Prolog 编程的知识。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多