Reputation: 61
I want to convert a list of pairs to two lists – first containing first elements of the pairs, second containing second elements of the pairs.
E.g.
[['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']]
should produce
List1 = ['Test1', 'Test1', 'Test2']
List2 = ['US', 'France', 'German']
I tried to use foreach
and come up with this function:
testfor:-
List = [['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']],
(
foreach(X,List) do
X=[F,S],
append([F],[],List1),
append([S],[],List2)
),
writeln(List1).
It doesn't work, I am confused. Where did I make a mistake? Of course, you can help me implement this function using your method (i.e. "don't use foreach
").
Upvotes: 1
Views: 5296
Reputation: 13574
Using maplist/4
, the whole iteration is hidden and you have to think just about the deconstruction of a single pair.
%zip(?FirstList, ?SecondList, ?PairList)
zip(Fst, Snd, Pair) :- maplist(pair, Fst, Snd, Pair).
%pair(?First, ?Second, ?Pair)
pair(Fst, Snd, [Fst, Snd]).
Use it thus:
?- zip(List1, List2, [['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']]).
List1 = ['Test1', 'Test1', 'Test2'],
List2 = ['US', 'France', 'German'].
Note that this is an advanced solution, though. First, getting to know the basic recursive solutions (presented by other answers) is really useful and I recommend it. Without a good grasp of recursion, Prolog is just one big hell. Actually, maplist
uses recursion too, it is just hidden from the caller.
Another thing to learn is how Prolog terms and unification work.
append
is completely unnecessary here. Moreover, it is harmful both performance-wise and readability-wise.Pairs are better represented using a functor, e.g. pair ['Test1', 'US']
becomes pair('Test1', 'US')
. Among other benefits, it is harder to accidentally mix up pairs and triplets. Using functors is somewhat similar to using types in other languages.
SWI-Prolog uses hyphen-minus as the functor for pairs. Due to having an operator declaration, hyphen-minus can be used in infix notation, too. E.g. pair ['Test1', 'US']
becomes 'Test1'-'US'
. Infix notation is just syntactic sugar for the usual prefix notation used for other functors (i.e. 'Test1'-'US' == -('Test1', 'US')
).
Finally, the foreach ... do
notation you tried to use looks like a loop construct from ECLiPSe, which is a language derived from Prolog. SWI-Prolog does not support this syntax.
Upvotes: 2
Reputation: 757
testfor([], [], []).
testfor([[X, Y]|T1], [X|T2], [Y|T3]):-testfor(T1, T2, T3).
Upvotes: 0
Reputation: 10672
pairs_to_lists([], [], []).
pairs_to_lists([E1-E2 | Tail], [E1 | Tail1], [E2 | Tail2]) :-
pairs_to_lists(Tail, Tail1, Tail2).
Usage:
?- pairs_to_lists(['Test1'-'US', 'Test1'-'France', 'Test2'-'German'], L1, L2).
L1 = ['Test1', 'Test1', 'Test2'],
L2 = ['US', 'France', 'German'].
Some comments:
[A, B]
use A-B
or pair(A, B)
.append([A], L1, L2)
is the same as L2 = [A | L1]
, the latter is more readable.Upvotes: 1
Reputation: 21990
Well
yoba( [], [], [] ).
yoba( [[Name1, Name2] | Tail], List1, List2 ) :-
append( [Name1], ListNew1, List1 ),
append( [Name2], ListNew2, List2 ),
yoba( Tail, ListNew1, ListNew2 ).
And
?- yoba([['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']], X, Y).
X = ['Test1', 'Test1', 'Test2'],
Y = ['US', 'France', 'German'].
Upvotes: 1