【问题标题】:How to move first N elements to the end of the list for each list in the list of lists如何将列表列表中每个列表的前 N ​​个元素移动到列表末尾
【发布时间】:2020-11-24 09:40:21
【问题描述】:

Prolog 中有什么方法可以从列表中移动前 N 个元素并将它们放在最后。 我想为列表列表中的每个列表执行此操作。示例:

输入:

move(3, [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1,2,3], [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]], R)

结果:

R = [[4, 5, 6, 7, 8, 9, 1, 2, 3], [1,2,3], [6, 7, 8, 9, 10, 11, 12, 3, 4, 5]]

我不知道,有人知道怎么做吗?

【问题讨论】:

  • 您是否尝试过使用单个列表而不是列表列表?然后,您可以将其映射到列表列表。
  • 不,我没有……你在说什么?我的意思是,你能展示一下吗?

标签: list prolog


【解决方案1】:

如果您执行以下查询,LeftRight 将绑定到两个列表,当它们连接在一起时,结果为 [1,2,3,4,5]

?- append(Left, Right, [1,2,3,4,5]).

上面的查询承认 6 个解决方案(Left 为空,列表 [1],列表 [1,2] 等)。您可以通过说 Left 恰好包含三个元素来限制查询:

?- length(Left, 3), append(Left, Right, [1,2,3,4,5]).
Left = [1, 2, 3]
Right = [4, 5]

这只有一种解决方案。

轮换包括生成一个列表,其中Left 部分位于Right 列表的右侧:

?- length(Left, 3), 
   append(Left, Right, [1,2,3,4,5]),
   append(Right, Left, Result).
Left = [1, 2, 3]
Right = [4, 5]
Result = [4, 5, 1, 2, 3]

您需要编写的第一个谓词如下:

rotate_left(List, Offset, Rotated) :-
  length(Left, Offset),
  append(Left, Right, List),
  append(Right, Left, Rotated).

然后您可以将此谓词应用于列表列表。


注意。你可以考虑改用这个版本:

rotate_left(List, Offset, Rotated) :-
    append(Left, Right, List),
    length(Left, Offset),
    append(Right, Left, Rotated).

更好一点,因为它允许Offset 是可变的:

[eclipse 2]: rotate_left([a, b, c, d], N, [c, d, a, b]).

N = 2
Yes (0.00s cpu, solution 1, maybe more) ? ;

No (0.00s cpu)

在原始版本中,length(Left, N) 的两个参数都是变量,并且它会不断生成越来越长的列表的答案。

【讨论】:

  • 循环排列可能有点用词不当,因为我们没有做Offset mod ListLength
  • 那么可能是 rotate_list,或者 rotate_left
【解决方案2】:

您正在对上面列表列表的每个元素执行相同的操作,即,获取前三个元素并将它们附加到后面。因此,如果您可以先定义操作本身,那么为列表列表执行此操作将很容易。

% If the predicate op/3 is already defined the you can easily define
% another one for a list the elements
op_for_lists([], _, []).
op_for_lists([X|Xs], N, [Y|Ys]) :-
    operation(X, N, Y), op_for_lists(Xs, N, Ys).

因此,如果您接受@coredump 的回答并将operation 替换为rotate_left,它将起作用。

您还可以将maplist/3yall 库中的lambda 一起使用,如下所示

op_for_lists(Xs, N, Ys) :-
  maplist({N}/[In, Out]>>operation(In, N, Out), Xs, Ys).

如果常量参数在开头会更容易,那么你可以简单地使用

maplist(operation(N), Xs, Ys)

获取列表列表的结果

【讨论】:

    【解决方案3】:

    这是我的方法:

    首先:提取起始元素的数量。这里 M 将作为一个计数器,告诉我们在提取起始元素时何时停止。基本情况中的 0 表示停止。

     s3(0,Rest,[], Rest):-!.
    s3(M,[H|T],[H|R], Rest):-
        M1 is M-1,
        s3(M1,T,R, Rest).
    

    第二个:我们需要追加Rest(J)[包含列表的剩余元素]和R(Q)[包含起始元素]。

    append(J,Q,L)
    

    第三:把代码全部放好。

    s3(0,Rest,[], Rest):-!.
    s3(M,[H|T],[H|R], Rest):-
        M1 is M-1,
        s3(M1,T,R, Rest).
    
    q1(M,[H|T],L):-
        s3(M,[H|T],Q,J),
        append(J,Q,L).
    

    示例:

    ?-q1(3,[3,4,5,6,7,8,9,10,11,12],L).
    L = [6, 7, 8, 9, 10, 11, 12, 3, 4, 5]
    
    ?-q1(3,[1,2,3,4,5],L).
    L = [4, 5, 1, 2, 3]
    

    现在您可以从这一点开始编写一个谓词,它可以分别处理每个列表并为您提供解决方案。

    【讨论】:

    • 如果初始列表本身具有重复元素,则此方法将不起作用。因此,您也可以扩展 s2 谓词来获取其余元素。看看gist.github.com/k3ut0i/f8ca3630ccf4360d37ba90099109dbdc。我刚刚扩展了您的 s2 以不忽略基本案例中的第二个参数。现在只需s3(N, ListIn, Head, Tail), append(Tail, Head, Ans) 即可为您提供解决方案。
    • 这真是太好了。我是一个新手,我基本上是在挑战自己,看看我是否有能力提出解决方案。我已经更新了我的解决方案。
    【解决方案4】:

    另一种选择是使用 partition/4(在 SWI Prolog 中):

    test(O):-
        L = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1,2,3], [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]],
        maplist(move(3),L,O).
    
    greater(N,L,E):-
        nth1(I,L,E),I > N.
    
    move(N,L,O):-
        partition(greater(N,L),L,LO,LP),
        append(LO,LP,O).
    
    ?- test(O).
    O = [[4, 5, 6, 7, 8, 9, 1, 2, 3], [1, 2, 3], [6, 7, 8, 9, 10, 11, 12, 3, 4, 5]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-10
      • 2015-02-10
      • 2023-03-17
      • 2016-06-16
      • 2013-11-14
      • 2011-06-22
      相关资源
      最近更新 更多