user1553248
user1553248

Reputation: 1204

How to check the type of an element in a list

My list (which in turn contains lists) contains many different types of elements (obj1(), obj2(), obj3..). I want to access each element in this list and do something only if the element I'm currently accessing is of type obj2(_).

listObj = [[ obj1(_), obj2(_), obj1(_) ],
          [ obj3, obj3, obj2(_), obj1(_)]],

foreach ((X, listObj)), 
%% if X is obj2(_) -> doSomething using x's _ value,
%% otherwise skip this element
).

Upvotes: 0

Views: 118

Answers (3)

CapelliC
CapelliC

Reputation: 60014

the easier way (but please note: Variables start Uppercase):

..., flatten(ListObj, F), member(obj2(V), F), process(V), ...

To avoid flattening the list, we must make a predicate, and introduce recursion:

nested_member(V, X) :-
    member(T, X),
    ( is_list(T) -> nested_member(V, T) ; V = T ).

with that

?- nested_member(obj2(V),[[1,[2,obj2(3),a],obj2(b),4]]).
V = 3 ;
V = b ;
false.

Upvotes: 0

Paulo Moura
Paulo Moura

Reputation: 18663

Using lists of lists usually hints at a bad representation. Several systems provide a flatten/2 library predicate over lists that may be useful, however, if you cannot avoid this representation. Assuming that the list of lists in your example have been flatted, you should be able to write a simple recursive predicate to walk over the list and process each element that satisfies your criteria. Something like:

process([]).
process([Element| Elements]) :-
    (   Element = obj2(Arg) ->
        do_something(Arg)
    ;   true
    ),
    process(Elements).

Details, however, will depend on several factors that you don't specify. For example, what does it mean if processing of an obj2(_) element fails? Failure of processing the list (as in the predicate sketched above)? Continue to the next element? Are the list elements independent or may share variables? Some Prolog systems also provide foreach/2 and forall/2 predicates that might be useful for a compact (but not necessarily more efficient) solution.

Upvotes: 3

magus
magus

Reputation: 1357

I think this is just a basic recursion question - how to iterate through a list, and use pattern matching on the head. If so, this should do

% case 1 - end recursion
listiter([]).

% case 2 - list head obj2 matches
listiter([obj2(Obj_2_Value)|T]) :-
    write(Obj_2_Value), nl,
    listiter(T).

% case 3 - case 2 failed, just recurse, ignoring head
listiter([_|T]) :-
    listiter(T).

In your 'real' code, replace, the 'write/nl' predicates with whatever you want to really do with obj2()'s value.

?listiter([obj1(brown), obj2(hello), obj3(fred), obj2(stack), obj4(bun), obj2(overflow)]).
hello
stack
overflow
true .

Or a shorter way, using the built-in maplist/1:

% match if item is obj2()
dosomething(obj2(Obj_2_Value)) :-
    write(Obj_2_Value), nl.

% not object 2 - still return true, but don't do anything
dosomething(_).


?- maplist(dosomething, [obj1(brown), obj2(hello), obj3(fred), obj2(stack), obj4(bun), obj2(overflow)]).
hello
stack
overflow
true .

Upvotes: 1

Related Questions