【问题标题】:Prolog - Extract a SublistProlog - 提取子列表
【发布时间】:2014-01-24 23:39:51
【问题描述】:

sublist(L1,L2,I,J)

我有一个列表,L1 正在传入,还有 2 个索引 IJ,我希望 L2 成为包含 IJ 之间元素的子列表。
如果J 超出范围,我希望它从I 到列表末尾。同样,如果I 小于0,我想让它从列表的开头到JI > J 返回空列表。

到目前为止我所拥有的:

sublist(_,[],I,J):-
    I > J.  
sublist(Xs,Ys,I,Length):-
    length(Xs,Length),
    N > L,
    sublist(Xs,Ys,I,J).  
sublist([X|_],[X],1,1).  
sublist([X|Xs],[X|Ys],1,J):-
    J > 1,
    J1 is J - 1,
    sublist(Xs,Ys,1,J1).  
sublist([_|Xs],Ys,I,J):-
    I > 1,
    I1 is I - 1,
    J1 is J - 1,
    sublist(Xs,Ys,I1,J1).

【问题讨论】:

  • 那么你到目前为止所拥有的有什么问题?这里的人不应该给你答案,而是给你解释。
  • @Rubens 哦,对不起,忘了包括。第二个谓词不起作用。它目前需要IJ 才能在列表中。

标签: list prolog


【解决方案1】:

你可以通过重新思考你的策略来解决这个问题。

首先,您的基本情况是什么?

  • 您最终将空列表作为输入
  • 你有I > J

在这两种情况下,您都可以将空列表附加到您目前拥有的任何内容中,并称其为好。

接下来,您关心的边缘情况是什么?

  • J 超出列表末尾
  • I 在列表开头之前

在第一种情况下,您只需遍历输入列表的末尾。在第二种情况下,您从输入列表的开头开始。

好的,让我们尝试实现它,我将使用累加器并将调用包装起来。

sublist(L1, L2, I, J):-
    sublist(L1, Temp, I, J, []),
    !,
    reverse(Temp, L2).

我们将输入列表L1(一个要统一的变量)作为我们的输出列表L2,以及索引IJ。我正在使用cut,这样我就不必担心其他解决方案的回溯,并且将其反转,因为累积的列表是反向构建的。

让我们处理基本情况。

空列表作为输入,只需将累加器与我们的输出列表统一即可。在这一点上,我们不关心指数。事实证明,这也满足了J 超出列表末尾的边缘情况。因为此时我们会将所有输入列表累加到累加器中,并且还剩下一个 J 值。

sublist([], L2, _I, _J, L2).

I > J 再次将累加器与我们的输出列表统一起来。我们不再关心输入列表。

sublist(_L1, L2, I, J, L2):-
    I > J.

现在是边缘情况。

J 超出列表末尾已在上面解决。

I 在列表开头之前,只需将该索引设置为 0,然后继续。

sublist(L1, L2, I, J, L2):-
    I < 0,
    sublist(L1, L2, 0, J, L2).

现在我们只需要实现实际的逻辑。我们只想从正确的I开始累积。因此,让我们减少I 并丢弃输入列表的各个部分,直到我们到达我们想要的位置。为了使索引的末尾匹配,我们还需要减少J。这样我们在索引之间保持相同的距离。

sublist([_L|Ls], L2, I, J, Acc):-
    I > 0,
    sublist(Ls, L2, I-1, J-1, Acc).

我们终于到了我们想去的地方。因此,让我们开始使用输入列表中的片段构建列表。这种情况一直持续到我们遇到一个基本案例。之后,累加器返回到原来的sublist 子句。

sublist([L|Ls], L2, I, J, Acc):-
    sublist(Ls, L2, I, J-1, [L|Acc]).

综上所述,我们最终得到:

sublist(L1, L2, I, J):-
    sublist(L1, Temp, I, J, []),
    !,
    reverse(Temp, L2).
sublist([], L2, _I, _J, L2).
sublist(_L1, L2, I, J, L2):-
    I > J.
sublist(L1, L2, I, J, L2):-
    I < 0,
    sublist(L1, L2, 0, J, L2).
sublist([_L|Ls], L2, I, J, Acc):-
    I > 0,
    sublist(Ls, L2, I-1, J-1, Acc).
sublist([L|Ls], L2, I, J, Acc):-
    sublist(Ls, L2, I, J-1, [L|Acc]).

我们可以这样测试它:

?- sublist([1,2,3,4,5], S, 0,3).
S = [1, 2, 3, 4].

?- sublist([1,2,3,4,5], S, -1,30).
S = [1, 2, 3, 4, 5].

?- sublist([1,2,3,4,5], S, 3,1).
S = [].

?- sublist([1,2,3,4,5], S, 3,3).
S = [4].

?- sublist([1,2,3,4,5], S, 3,4).
S = [4, 5].

【讨论】:

  • +1 出色、深入的回答。稍微担心缺少is/2,但显然&lt;/2&gt;/2 使用算术表达式。
  • 以自上而下的方式构建结果更加 Prologish,可以争论,并且可以/应该同样直观。 :) 最后也不需要反转。
【解决方案2】:

我认为您在第二个子句中有一些错字。试试这个(未经测试的)更正,需要满足您的要求

如果 J 超出范围,我希望它从 I 到列表的末尾。

sublist(Xs,Ys,I,J):-
    length(Xs,Length),
    J > Length,
    sublist(Xs,Ys,I,Length).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多