Reputation: 42409
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
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
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
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
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
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