2

Let's say I have a list of numbers and I want to split this list into two sublists: one for odd numbers and another one for evens.

evens, odds = [], []
for e in numbers:
    if e % 2 == 0:
        evens.append(e)
    else:
        odds.append(e)

I wonder if there is a one-liner for this problem while keeping the same order of complexity.

I tried using itertools.groupby but the list needs to be ordered first so I'd be achieving a O(2n) rather than O(n):

def is_even(n):
    return n % 2 == 0

lst = sorted(lst, key=is_even)
grouper = itertools.groupby(lst, key=is_even)
lst1, lst2 = [list(v) for k, v in grouper]
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
dabadaba
  • 9,064
  • 21
  • 85
  • 155
  • 3
    As a side note, `O(2n)` and `O(n)` have the same magnitude and most of the time can be treated as equal. – DeepSpace Jul 28 '17 at 10:19
  • O(2n) is the same as O(n), just saying... – Ecir Hana Jul 28 '17 at 10:19
  • @DeepSpace yeah I know, but it's still twice as slow, it just bothers me and I'd rather do it as efficient as possible – dabadaba Jul 28 '17 at 10:21
  • 1
    And by the way, while we are at it, your `groupby` solution is not `O(2n)`. Since `sorted` is using quicksort the complexity of your second solution is (on average) `O(nlogn + n)`. – DeepSpace Jul 28 '17 at 10:28
  • @DeepSpace true that I really didn't stop to think what sorting algorithm was being used, my point was that it added extra level of complexity that the first loop doesn't introduce – dabadaba Jul 28 '17 at 10:29
  • @DeepSpace quicksort -> timsort. And by the way, the first solution is not even close to O(n) as the `append` might re-allocate the lists, leading to O(n^2). – Ecir Hana Jul 28 '17 at 10:31

2 Answers2

6

How about using the ternary operator prior to append:

evens, odds = [], []
for e in numbers:
    (odds if e % 2 else evens).append(e)

Of course you could do this inside a list comprehension, but it's not Pythonic to use a comprehension for it's side-effects because you create a potentially large unwanted list of None values. You could instead use the itertools consume recipe if you want to take that route.

Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
3

You could abuse list comprehension, but please don't do that in production code.

nums = range(6)
odds = []
evens = []
[odds.append(num) if num % 2 == 1 else evens.append(num) for num in nums]
print(odds, evens)
# [1, 3, 5] [2, 4]
DeepSpace
  • 78,697
  • 11
  • 109
  • 154