Maverickgugu
Maverickgugu

Reputation: 777

Erlang list vs tuple comparison

Assume that there is an erlang list of lists:

Note that the size of the lists are fixed. In this case 3.

A = [[1,2,3],[4,5,6],[1,8,3],[1,9,3]]

I am trying to write function which will drop all the elements which are of the form [1,_,3]. So my expected output would be of the form: [[4,5,6]]

One solution which I could think about was the lists:dropwhile() function which can be used.

I am having trouble constructing the predicate function. Is it easier to convert every element into a tuple and then do the comparison? If so, there is no proper way I could omit the middle element.

Can you please help me arrive at the solution? Any other efficient approach would also be highly appreciated.

Thanks in advance!

Edit: Question Extenstion:

Assume two erlang list of lists:

A = [[1,2,3], [2,3,4], [4,5,6]]

B = [[1,4,3], [4,7,6], [7,8,9], [4,9,7], ]

The output F(A,B) = [[7,8,9], [4,9,7]]

F is defined to be a function, which removes from list B all the elements which are matching any one of the elements in list A in the first and the third position.

In this case, all those elements in list B which are matching [1, _ ,3] or [2, _ , 4] or [4 , _ , 6] are deleted from the list to give the resulting list.

I am struggling to write F.

Upvotes: 3

Views: 2161

Answers (3)

Maverickgugu
Maverickgugu

Reputation: 777

I managed to come up with a solution for the extended question:

Given A and B as in question:

F(A,B) ->
    lists:filter(fun(X) -> predicate(X,B) end, A).

predicate(X, B) ->
    Xr = lists:delete(lists:nth(2,X),X),
    Br = lists:map(lists:delete(lists:nth(2,Y),Y),B),
    lists:member(Xr, Br).

This lists library is so cool.. :)

Upvotes: 1

I GIVE CRAP ANSWERS
I GIVE CRAP ANSWERS

Reputation: 18879

Your filter function needs some help:

lists:filter(fun([1, _, 3]) -> false; (_) -> true end,
             [[1,2,3],[4,5,6],[1,8,3],[1,9,3]]).

You need the match in the function head to make this work.


As for having multiple filters, you can use a map of funs (not tested):

composed_filter(Tests, Input) ->
  lists:filter(fun(X) -> lists:all([F(X) || F <- Tests]) end,
               Input).

For using multiple filters, you can do:

filter(fun([1,_,3]) -> true;
          ([5,_,7]) -> true;
          ([9,_,13]) -> true;
          (_) -> false end, Input)
% or
composed_filter([fun([1,_,3]) -> true; (_) -> false end,
                 fun([5,_,7]) -> true; (_) -> false end,
                 fun([9,_,13]) -> true; (_) -> false end],
                Input)

Though unless you need a programmable dynamic composability, you should probably just use the first. Another way, again is to run the composition with a function rather than having a specialized composed_filter. This is a more combinator-style approach which the Haskell crowd would love. Note that the above functions are slightly different. The first has orelse semantics whereas the latter has andalso semantics. That is in the first case, you get the element if one or more of the patterns match, whereas in the latter case, you only get a result if all the patterns/funs match. You could use lists:any/2 to obtain a composed_any_filter.

Upvotes: 12

Fred Foo
Fred Foo

Reputation: 363607

dropWhile can only return a prefix of the list, so it's not going to work. Use filter instead.

Upvotes: 3

Related Questions