Frage

I'm wondering if there is not a way to compute the complement of a list comprehension in Python. Something like:

evens = [i in range(10) if i % 2 == 0]
odds  = [i in range(10) if i % 2 != 0]

is there a way to get both evens and odds in one call? For a very large list, or a more expensive if statement, I think this would save a lot of time.

War es hilfreich?

Lösung

I believe this question has been asked before, but I am not finding the link currently.

If you are trying to get more than one predicate and you only want to iterate once over the original generator, then you will have to use a simple for loop.

evens = []
odds = []

for i in xrange(10):
   if i % 2 == 0: evens.append(i)
   else: odds.append(i)

As @dawg pointed out, the logic inside the loop can be made more concise using clever indexing.

for i in xrange(10):
   (evens,odds)[i%2].append(i)

Andere Tipps

itertools.groupby is what I'd use.

In [1]: import itertools as it

In [2]: key = lambda i: i%2 == 0

In [3]: l = list(range(10))

In [4]: l.sort(key=key)

In [5]: [list(i[1]) for i in it.groupby(l, key=key)]
Out[5]: [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8]]

I would do one of the following:

evens = [i in range(10) if i % 2 == 0]
odds  = [i in range(10) if i not in evens]

Or with better performances:

evens = [i in range(10) if i % 2 == 0]
evens_set = set(evens)
odds = [i in range(10) if i not in evens_set]

Working with set is better in performance, as the not in query costs O(1) instead of O(n) in lists

In short, you can get both True and False cases in one call, but you'd still need to split them into two lists. You could do

range_10 = range(10)
odds = range_10[1::2]
evens = range_10[::2]

but the benefit of that would be negligible. (In fact, you'd be creating three lists instead of two). You'd only want to do that if the cost of range(10) was so high that it would offset creating two lists.

Using slicing like I did should be slightly faster than using a test and explicitly appending.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top