Roger Roger
Roger Roger

Reputation: 45

Getting every second item from a tuple within a list of tuples

So I have recently started using prolog, since I am getting into using AI and FOL. I have noticed quite a few differences with other languages I have used such as Python and Java and I am having a difficult time trying to "compare" these languages.

The main problem I am having is that I have no idea how to build a rule to get a list of the second item of the tuples in a list.

The input is a list of tuples, for example: [(1,aa),(2,bb),(3,cc),(4,dd)].

I am trying to write a function such that the output is a LIST OF SECOND ITEM OF EVERY TUPLE within the list, namely [aa, bb, cc, dd]

I have already tried doing something along the lines of "extract_second_item([(1,aa),(2,bb),(3,cc),(4,dd)], [(_ , output)|_])". But when I run that function, it only returns the second item of the first tuple (aa) but apparently not the rest.

Thanks!

Upvotes: 1

Views: 727

Answers (2)

CapelliC
CapelliC

Reputation: 60024

Actually, a tuple is a compound:

?- write_canonical((a,b,c)).
','(a,','(b,c))
true.

so arg/3 is pretty functional to extract the second argument by position from a tuple:

?- arg(2,(a,b),X).
X = b.

the you can solve your problem in a compact way, using a lambda expression

?- maplist([X,Y]>>arg(2,X,Y), [(1,aa),(2,bb),(3,cc),(4,dd)], L).
L = [aa, bb, cc, dd].

Tuples aren't widely used in Prolog, indeed the problem has a simpler solution, directly applying pattern matching:

?- maplist([X,Y]>>(X=(_,Y)), [(1,aa),(2,bb),(3,cc),(4,dd)], L).
L = [aa, bb, cc, dd].

Pattern matching could be pushed in the lambda arguments:

?- maplist([(_,Y),Y]>>true, [(1,aa),(2,bb),(3,cc),(4,dd)], L).
L = [aa, bb, cc, dd].

Instead of library(yall), you could choose library(lambda), trading speed for portability:

?- use_module(library(lambda)).
true.

?- maplist(\X^Y^(X=(_,Y)), [(1,aa),(2,bb),(3,cc),(4,dd)], L).
L = [aa, bb, cc, dd].

In SWI-Prolog, this requires you install pack(lambda),

?- pack_install(lambda).

Upvotes: 2

coder
coder

Reputation: 12972

You need to use simple recursion:

extract_second_item([], []).
extract_second_item([(_,X)|T], [X|T2]):- extract_second_item(T,T2).

Now querying:

?- extract_second_item([(1,aa),(2,bb),(3,cc),(4,dd)], L).
L = [aa, bb, cc, dd].

Another great way proposed by @lurker is to use maplist/3:

Firstly we define a simple predicate that returns the second item from a tuple:

second_item((_,X), X).

Then we map second_item/2 to each tuple in the list using maplist/3:

?-maplist(second_item, [(1,aa),(2,bb),(3,cc),(4,dd)], L).
L = [aa, bb, cc, dd].

Upvotes: 3

Related Questions