Justin Poehnelt
Justin Poehnelt

Reputation: 3469

List Comprehension to Sublists

As a beginner computer science student I was assigned to write a function to sort a list of even and odd numbers into two sublists. Wait... don't down vote me. I have been learning on my own a bit and experimenting with list comprehension and timeit and was wondering if I could recreate this with list comprehension to do something a bit more challenging instead.

I've figured out how to use list comprehension to flatten sublists, but not the other way around. Is it possible?

def odd_even_filter(numbers):
    even = []
    odd = []
    for i in numbers:
        if i % 2 == 0:
            even.append(i)
        else:
            odd.append(i)
    return [even, odd]

odd_even_filter([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>[[2,4,6,7],[1,3,5,7,9]]

Just trying to see if i can take a flat list and generate nested lists using list comprehension. It may not be worth it and not the python way, but just experimenting.

Upvotes: 3

Views: 1030

Answers (5)

Apalala
Apalala

Reputation: 9224

If you're aiming for the shortest, yet pythonic answer, How about?

odd = [i for i in numbers if i % 2]  # this is O(n)
even = list(set(numbers) - set(odd)) # this is O(n log n)

An inefficient, but still clear alternative is:

even = numbers - odd # this is O(n^2)

An O(n) alternative (the best?) would be:

odd = [i for i in numbers if i % 2] # this is O(n)
even = [i for i in numbers if not i % 2] # this is O(n)

Upvotes: 2

SZIEBERTH Ádám
SZIEBERTH Ádám

Reputation: 4184

Based on ssm's post:

>>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [list(filter(lambda x: x%2==0, l)), list(filter(lambda x: x%2==1, l))]
[[2, 4, 6, 8], [1, 3, 5, 7, 9]]

This solution is slow though.

Upvotes: 0

James Sapam
James Sapam

Reputation: 16940

if your number are in sequence you can even use slice:

>>> [r[1::2],r[2::2]]
[[1, 3, 5, 7, 9], [2, 4, 6, 8]]
>>>

Upvotes: 0

ssm
ssm

Reputation: 5373

There is always a tradeoff between readability and compactness in code. In this case, I believe the answer by devnull is excellent. He uses list comprehensions and Python if expression resulting in something very readable in a single line. If your test criterion is more stringent, it is generally more useful to separate out the conditions into their own functions. For your example, these would be:

def even(x): return x%2 == 0
def odd(x) : return x%2 != 0

and then use them for filtering out the results like so:

def oddEvenFilter(x): return [filter(even, x), filter(odd, x)]

These are three lines of code, but in combination is very readable.

Upvotes: 1

Justin Poehnelt
Justin Poehnelt

Reputation: 3469

This works, not easier to read at all, but it is possible with range being the number of subgroups, 2 for even and odd.

return [[ n for n in numbers if n % 2 == 0] if i == 0 else [ n for n in numbers if n % 2 != 0] for i in range(2)]

Ran this through timeit and it takes twice as long which is to be expected. devnull's answer takes a little bit longer too.

def odd_even_filter(numbers):
    even = []
    odd = []
    for i in numbers:
        if i % 2 == 0:
            even.append(i)
        else:
            odd.append(i)
    return [even, odd]

def odd_even_filter_2(numbers):
    return [[ n for n in numbers if n % 2 == 0] if i == 0 else [ n for n in numbers if n % 2 != 0] for i in range(2)]

def odd_even_filter_3(numbers):
    even = []
    odd = []
    [ odd.append(n) if n % 2 != 0 else even.append(n) for n in numbers]
    return [even,odd]

print(timeit.timeit('odd_even_filter([1, 2, 3, 4, 5, 6, 7, 8, 9])', setup="from __main__ import odd_even_filter" )) 
print(timeit.timeit('odd_even_filter_2([1, 2, 3, 4, 5, 6, 7, 8, 9])', setup="from __main__ import odd_even_filter_2" ))
print(timeit.timeit('odd_even_filter_3([1, 2, 3, 4, 5, 6, 7, 8, 9])', setup="from __main__ import odd_even_filter_3" ))

>>2.2804439414858675
>>4.190625469924679
>>3.0541580641135733

Upvotes: 0

Related Questions