Gabriel
Gabriel

Reputation: 42409

Make this simple for/if block more pythonic

I need to store in a list the indexes of those values in 3 lists which exceed a given maximum limit. This is what I got:

# Data lists.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]

# Maximum limit.
max_limit = 20.

# Store indexes in list.
indexes = []
for i, a_elem in enumerate(a):
    if a_elem > max_limit or b[i] > max_limit or c[i] > max_limit:
        indexes.append(i)

This works but I find it quite ugly. How can I make it more elegant/pythonic?

Upvotes: 1

Views: 129

Answers (5)

meshy
meshy

Reputation: 9116

>>> maximums = map(max, zip(a, b, c))
>>> [i for i, num in enumerate(maximums) if num > max_limit]
[2, 5, 6, 8]

Old answer

Previously, I posted the mess below. The list comp above is much more manageable.

>>> next(zip(*filter(lambda i: i[1] > max_limit, enumerate(map(max, zip(a, b, c))))))
(2, 5, 6, 8)

Upvotes: 2

msw
msw

Reputation: 43517

I like the exceeders = line best myself

import collections

# Data lists.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]

Triad = collections.namedtuple('Triad', 'a b c')
triads = [Triad(*args) for args in zip(a, b, c)]

triads = [t for t in zip(a, b, c)]  # if you don't need namedtuple

# Maximum limit.
max_limit = 20.

# Store indexes in list.
indexes = [for i, t in enumerate(triads) if max(t) > max_limit]
print indexes

# store the bad triads themselves in a list for
# greater pythonic

exceeders = [t for t in triads if max(t) > max_limit]
print exceeder

As I commented above, using parallel arrays to represent data that are related makes simple code much less simple than it need be.

added in response to comment

Perhaps I gave you too many alternatives, so I shall give only one way instead. One feature that all of the answers have in common is that they fuse the separate "data lists" into rows using zip:

triads = [t for t in zip(a, b, c)]
exceeders = [t for t in triads if max(t) > max_limit]

That's it: two lines. The important point is that storing the index of anything in a list is a C-style way of doing things and you asked for a Pythonic way. Keeping a list of indices means that anytime you want to do something with the data at that index, you have to do an indirection. After those two lines execute, exceeders has the value:

[(5, 1, 32), (8, 784, 7), (78, 43, 2), (6, 2, 23)]

Where each member of the list has the "column" of your three data rows that was found to exceed your limit.

Now you might say "but I really wanted the indices instead". If that is so, there is another part of your problem which you didn't show us which also relies on list indexing. If so, you are still doing things in a C/C++/Java way and "Pythonic" will remain evasive.

Upvotes: 2

schesis
schesis

Reputation: 59168

You could replace your for loop with:

indexes = []
for i, triplet in enumerate(zip(a, b, c)):
    if any(e > max_limit for e in triplet):
        indexes.append(i)

... which you could then reduce to a list comprehension:

indexes = [i for i, t in enumerate(zip(a, b, c)) if any(e > max_limit for e in t)]

... although that seems a little unwieldy to me - this is really about personal taste, but I prefer to keep listcomps simple; the three-line for loop is clearer in my opinion.

As pointed out by user2357112, you can reduce the apparent complexity of the list comprehension with max():

indexes = [i for i, t in enumerate(zip(a, b, c)) if max(t) > max_limit]

... although this won't short-circuit in the same way that the any() version (and your own code) does, so will probably be slightly slower.

Upvotes: 6

Pavel
Pavel

Reputation: 7562

m = lambda l: [i for i, e in enumerate(l) if e>max_limit]
indexes = sorted(set(m(a) + m(b) + m(c)))

Upvotes: 1

limasxgoesto0
limasxgoesto0

Reputation: 4793

You could try

if max(a_elem, b[i], c[i]) > max_limit:
    indexes.append(i)

The logic here is finding out if any one of these three values needs to be greater than max_limit. If the greatest element of these three is greater than max_limit, your condition is satisfied.

Upvotes: 2

Related Questions