How to predicate elements in a list based on element type

264 Views Asked by At

Given a list of the format,

[item(a), item(b), item(c), other(d), other(e) ...]

where the number of items isn't fixed, nor is the number of others, but items always precede other, how do I split the list so that I can pass the items and the others into different predicates.

I've been trying to find ways to split the list based on the elements but can't figure out a way to do so.

I need to write a predicate that will take this list, and then pass the items to an itemPredicate, and the others to an otherPredicate.

If there's any other info I can provide please let me know.

3

There are 3 best solutions below

2
Lorenz On BEST ANSWER

A simple split predicate that separates item(_) from other(_) could work as follows:

split([], [], []).
split([item(A) | T], [item(A) | IT], OL) :- split(T, IT, OL).
split([other(A) | T], IL, [other(A) | OT]) :- split(T, IL, OT).

And use it like this:

?- split([item(1), other(2), other(3), item(4), other(5)], X, Y).
X = [item(1), item(4)],
Y = [other(2), other(3), other(5)].

It doesn't even require that items always precede others.

1
false On

Let's start with a predicate to classify elements. What about

item_t(item(_), true).
item_t(other(_), false).

Note that this predicate has an extra argument for its truth value. It only accepts item(_) or other(_) elements. It fails entirely if something like unfit(x) is presented. Now imagine, we have a predicate takeWhilet/3 we could now write

?- takeWhilet(item_t, [item(a), item(b), item(c), other(d), other(e)], Xs).

takeWhilet(_P_1, [], []).
takeWhilet(P_1, [E|_], []) :-
   call(P_1, E, false).
takeWhilet(P_1, [E|Es], [E|Fs]) :-
   call(P_1, E, true),
   takeWhilet(P_1, Es, Fs).

More beautifully using library(reif)s if_/3:

takeWhilet(_P_1, [], []).
takeWhilet(P_1, [E|Es], Fs0) :-
   if_( call(P_1, E)
      , ( Fs0 = [E|Fs], takeWhilet(P_1, Es, Fs) )
      , Fs0 = [] ).

Now, we might define other_t/2 similarly...

0
joel76 On

You can generalize to any type of items

work(item,L) :-
    format('args of \'item\' ~w~n', L).

work(other,L) :-
    format('args of \'other\' ~w~n', L).

work(anything, L) :-
    format('args of \'anything\' ~w~n', L).

work_element(Item) :-
    Item =.. [A|L],
    work(A, L).

my_split(In) :-
    maplist(work_element, In).

For example :

?- my_split([item(a), item(b), item(c), other(d), other(e) , item(f), other(g)]).
args of 'item' a
args of 'item' b
args of 'item' c
args of 'other' d
args of 'other' e
args of 'item' f
args of 'other' g
true