序言:获得包含两个子列表的列表,其中包含奇数位置元素和偶数位置元素。如何改进此代码

时间:2019-06-11 14:01:23

标签: prolog

我想问一下,是否有人知道如何改进(如果不是最佳的话)此代码。

这个想法是,您有一个元素列表,我想返回一个列表,其中包含两个子列表,第一个子列表应包含列表中奇数个位置中包含的元素,第二个子列表应该包含包含在列表偶数位置的元素。

一些例子:

?-evenAndOdd([1,2,3,4,5],[[1,3,5],[2,4]])
True.

?-evenAndOdd([a,b,c,d,e],[[a,c,e],[b,d]]).
True.

我实现的代码是下一个:

evenAndOdd([],[]).

evenAndOdd([H|R],NL):-
    evenAndOddRec([H|R], [[],[]],1,NL).


evenAndOddRec([], [LOdd,LEven],_,[LOdd,LEven]).

evenAndOddRec([H|R],[LOdd,LEven],Pos,NL):-
    \+ even(Pos),
    !,
    NPos is Pos +1,
    append(LOdd,[H],NLOdd),
    evenAndOddRec(R,[NLOdd,LEven],NPos,NL).

evenAndOddRec([H|R],[LOdd,LEven],Pos,NL):-
    NPos is Pos + 1,
    append(LEven, [H], NLEven),
    evenAndOddRec(R,[LOdd, NLEven],NPos,NL).



even(N):-
    N mod 2 =:=0.

2 个答案:

答案 0 :(得分:4)

通过一次获取两个元素(并考虑元素中具有奇数个元素的情况),可以隐式确定递归时的偶数和奇数值:

evenAndOdd(L, [LOdd, LEven]):-
  evenAndOdd(L, LOdd, LEven).

evenAndOdd([], [], []).
evenAndOdd([Odd], [Odd], []).
evenAndOdd([Odd,Even|Tail], [Odd|LOdd], [Even|LEven]):-
  evenAndOdd(Tail, LOdd, LEven).

答案 1 :(得分:3)

代码不是最佳的一个征兆是,如果您要求在-,+,+实例化模式中寻求其他解决方案,它将陷入困境:

?- evenAndOdd(X, [[1,3,5], [2,4,6]]).
X = [1, 2, 3, 4, 5, 6] ;
<time passes>

在Prolog中手动尝试将列表与索引匹配时,这种情况经常发生。

从风格上讲,当我只有三个参数而不是两个参数时,我不希望返回一个仅包含两个列表的列表。毕竟,这是三个列表,组合列表以及偶数和奇数项之间的关系。

此外,只是盯着它,我不确定为什么这里需要任何算术或任何削减。这就是我的实现方式:

evenAndOdd([], [], []).
evenAndOdd([O], [O], []).
evenAndOdd([O,E|Rest], [O|ORest], [E|ERest]) :- evenAndOdd(Rest, ORest, ERest).

这适用于许多实例:

?- evenAndOdd([1,2,3,4,5,6], O, E).
O = [1, 3, 5],
E = [2, 4, 6].

?- evenAndOdd([1,2,3,4,5], O, E).
O = [1, 3, 5],
E = [2, 4] ;
false.

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

?- evenAndOdd(X, [1,3,5], [2,4,6]).
X = [1, 2, 3, 4, 5, 6].

?- evenAndOdd(X, [1,3,5], [2,4,6,8]).
false.

?- evenAndOdd([1,2,3,4,5,6], X, [2,4,6,8]).
false.

?- evenAndOdd([1,2,3,4,5,6], X, [2,4,6]).
X = [1, 3, 5].