To partition a list C
into a list of odd and even elements based on the ordinal position of the element within the list (its *index), this should the trick, if you count the first item in the list as odd (having an index of 1):
check( [] , [] , [] ) . % the empty list has neither an even nor an odd element.
check( [O] , [] , [O] ) . % a list of length 1 has only an odd element
check( [O|Os] , [E|Es] , [O,E|Xs] ) :- % a list of length > 1 has both an even and an odd element
check(Os,Es,Xs) . % - park them on the respective lists and recurse down.
If, on the other hand, you want to count the first item as even, (having an index of 0), it's not much different:
check( [] , [] , [] ) . % the empty list has neither an even nor an odd element.
check( [] , [E] , [E] ) . % a list of length 1 has only an even element
check( [O|Os] , [E|Es] , [E,O|Xs] ) :- % a list of length > 1 has both an even and an odd element
check(Os,Es,Xs) . % - park them on the respective lists and recurse down.
You can also accomplish the same thing by using a helper predicate with a flag that toggles to indicate state:
check( Os , Es , Xs ) :- % to partition list C into odd and even components...
check( odd , Os , Es , Xs ) . % - just invoke the helper with an appropriate seed value.
check( _ , [] , [] , [] ) . % we're done when we hit the end of the list.
check( odd , [X|Os] , Es , [X|Xs] ) :- % otherwise, place the head of the source list on the odd result list
check( even , Os , Es ,Xs ) . % - and recurse down, toggling state to even.
check( even , Os , [X|Es] , [X|Xs] ) :- % otherwise, place the head of the source list on the even result list
check( odd , Os , Es ,Xs ) . % - and recurse down toggling state to odd.
You'll note that in the above example, we've seeded the helper with odd
to indicate that the 1st element has an odd position (1-relative). Just switch the seed value to even
if you want the first element to have an even position (0-relative).
However... There's a simpler way: on each recursion, just switch the position of the two result lists:
check( [] , [] , [] ) .
check( [X|As] , Bs , [X|Cs] ) :- check( Bs , As , Cs ) .
Sweet!