跳过列表元素列表

时间:2017-09-30 08:02:56

标签: list prolog

我有这个嵌套列表:

list = [[1, 2, 3, 4], 
        [2, 7, 2, 1], 
        [3, 3, 7, 5], 
        [4, 4, 1, 7]]

我正试图跳过这个嵌套列表的第一个列表,以及每个列表的第一个元素。我希望它变成这样:

list = [[7, 2, 1], 
        [3, 7, 5], 
        [4, 1, 7]]

到目前为止,我有这个:

% skip first list in list of lists
skip_first_list([_|Tail], Tail).

% attemping to skip first element in each of the lists
skip_first_list([[_ | HeadTail] | Tail], X) :-
    skip_first_list(Tail, R),
    append(R, [HeadTail], X).

哪个不能产生正确的结果:

?- skip_first_list([[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]], X).
X = [[2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]] ;
X = [[3, 3, 7, 5], [4, 4, 1, 7], [2, 3, 4]] ;
X = [[4, 4, 1, 7], [7, 2, 1], [2, 3, 4]] ;
X = [[3, 7, 5], [7, 2, 1], [2, 3, 4]] ;
false.

而我正在回答这个问题:

X = [[7, 2, 1], [3, 7, 5], [4, 1, 7]]

我的结果到目前为止似乎显示我正在以反向/错误的顺序追加,我该如何解决这个问题?我真的不明白Prolog评估表达式的顺序。任何任何人将不胜感激。

1 个答案:

答案 0 :(得分:3)

规范是你提供一份清单列表:

  • 忽略第一个子列表(不是输出的一部分);和
  • 对于其余的子列表,所有头部也会被忽略。

所以我们最好把它分成两个谓词:

  • remove_heads/2,删除所有子列表的头部;和
  • remove_upper_left/2删除第一个子列表,然后使用上面的谓词弹出子列表的头部。

我们可以使用递归来执行remove_heads/2

remove_heads([],[]).
remove_heads([[_|H]|T],[H|T2]) :-
    remove_heads(T,T2).

最后我们的remove_upper_left/2忽略了列表的头部,并用尾巴调用remove_heads

remove_upper_left([_|T],T2) :-
    remove_heads(T,T2).

或完整:

remove_heads([],[]).
remove_heads([[_|H]|T],[H|T2]) :-
    remove_heads(T,T2).

remove_upper_left([_|T],T2) :-
    remove_heads(T,T2).

然后产生:

?- remove_upper_left([[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]],X).
X = [[7, 2, 1], [3, 7, 5], [4, 1, 7]].

也在相反的方向工作:

?- remove_upper_left(X, [[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]]).
X = [_G1364, [_G1370, 1, 2, 3, 4], [_G1376, 2, 7, 2, 1], [_G1382, 3, 3, 7, 5], [_G1388, 4, 4, 1|...]].

所以这里它为每个列表添加一个变量,并将一个变量(可能是一个子列表)预先添加到输出中。

此外,我们这里有两个谓词,价格为一:如果我们想在列表列表中弹出所有子列表的头部,我们也可以在将来使用remove_heads/2