views:

216

answers:

7

I want to filter elements from a list of lists, and iterate over the elements of each element using a lambda. For example, given the list:

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

suppose that I want to keep only elements where the sum of the list is greater than N. I tried writing:

filter(lambda x, y, z: x + y + z >= N, a)

but I get the error:

 <lambda>() takes exactly 3 arguments (1 given)

How can I iterate while assigning values of each element to x, y, and z? Something like zip, but for arbitrarily long lists.

thanks,

p.s. I know I can write this using: filter(lambda x: sum(x)..., a) but that's not the point, imagine that these were not numbers but arbitrary elements and I wanted to assign their values to variable names.

A: 

Try something like this:

filter(lambda a: a[0] + a[1] + a[2] >= N, a)
kgiannakakis
I want to assign them variable names, I think the list indexing notation is hard to read and can lead to bugs
If you care about this particular example, use `sum(a)`.
Debilski
+5  A: 

You can explicitly name the sublist elements (assuming there's always a fixed number of them), by giving lambda a tuple as its argument:

>>> a = [[1,2,3],[4,5,6]]
>>> N = 10
>>> filter(lambda (i, j, k): i + j + k > N, a)
[[4, 5, 6]]

If you specify "lambda i, j, k" as you tried to do, you're saying lambda will receive three arguments. But filter will give lambda each element of a, that is, one sublist at a time (thus the error you got). By enclosing the arguments to lambda in parenthesis, you're saying that lambda will receive one argument, but you're also naming each of its components.

rbp
Edited to expand a bit on the explanation.
rbp
This still seems a lot less readable to me than the equivalent list comprehension.
Mike Graham
I agree, actually. Only rarely do I prefer filter (or map, or reduce) to list comprehensions. I just gathered from the question that he preferred it for some reason.Edit: Although, on this particular instance, I do believe it's clear enough...
rbp
I tend to reserve `map` and `filter` for cases where I already have the function defined, where it actually saves me some effort. This case isn't super unclear or anything, but it does use one somewhat obscure language feature in unpacking the lists.
Mike Graham
Interestingly, I usually find filter usage itself less desirable than the unpacking, which I think is a very nice feature, as in "a, (b, c, d), e = [1, (2, 3, 4), 5]
rbp
Tuple unpacking in the argument list was removed in Python 3.0, so this solution is restricted to the 2.x series.http://www.python.org/dev/peps/pep-3113/
Ray
A: 

Use a function instead of a lambda, then myVar = a[0], etc.

BlueRaja - Danny Pflughoeft
+1  A: 

You can do something like

>>> a=[[1,2,3],[4,5,6]]
>>> filter(lambda (x,y,z),: x+y+z>6, a)
[[4, 5, 6]]

Using the deconstruction syntax.

moshez
A: 

How about this?

filter(lambda b : reduce(lambda x, y : x + y, b) >= N, a)

This isn't answering the question asked, I know, but it works for arbitrarily-long lists, and arbitrarily-long sublists, and supports any operation that works under reduce().

Benjamin Geiger
`reduce(lambda x, y : x + y, b)` works almost the same as `sum(b)`, but is uglier, longer, and harder to read and write.
Mike Graham
Yes, but it can be generalized to any binary function.That being said, your response makes more sense.
Benjamin Geiger
+9  A: 

Using lambda with filter is sort of silly when we have other techniques available.

In this case I would probably solve the specific problem this way (or using the equivalent generator expression)

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> [item for item in a if sum(item) > 10]
[[4, 5, 6]]

or, if I needed to unpack, like

>>> [(x, y, z) for x, y, z in a if (x + y) ** z > 30]
[(4, 5, 6)]

If I really needed a function, I could use argument tuple unpacking (which is removed in Python 3.x, by the way, since people don't use it much): lambda (x, y, z): x + y + z takes a tuple and unpacks its three items as x, y, and z. (Note that you can also use this in def, i.e.: def f((x, y, z)): return x + y + z.)

You can, of course, use assignment style unpacking (def f(item): x, y, z = item; return x + y + z) and indexing (lambda item: item[0] + item[1] + item[2]) in all versions of Python.

Mike Graham
A: 

Ok, obviously you know that you can use sum. The goal of what you are trying to do seems a bit vague, but I think that the optional parameter syntax might help you out, or at least give you some inspiration. If you place a * before a parameter, it creates a tuple of all of itself and all of the remaining parameters. If you place a ** before it, you get a dictionary.

To see this:

def print_test(a,b,c,*d):
    print a
    print b
    print c
    print d

print_test(1,2,3,4,5,6)

prints

1
2
3
(4, 5, 6)

You can use this syntax with lambda too.

Like I said, I'm not sure exactly what you are trying to do, but it sounds like this might help. I don't think you can get local variable assignments in lambda without some hacking, but maybe you can use this to assign the values to variables somehow.

Edit: Ah, I understand what you are looking for moreso now. I think you want:

lambda (a, b, c): a+b+c > N
mellort