Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List Comprehension Append Odds Twice Evens Once

I am in the process of learning list comprehensions and stumbled into a type of problem that I cannot find resources to adequately understand.

The problem stems from the following question: We have an Array [1,2,3,8,9] and want to create an expression that would return each odd number twice, while even numbers are only returned once.

Note: there's also a hint that I could create nested lists but that so far has not helped me pinpoint how that would serve me.

The output of the appropriate algorithm should be: [1,1,2,3,3,8,9,9]

Using a loop, I could do what I want like this:

OtherNumList = [1, 2, 3, 8, 9]
OtherNumList2 = []
for i in OtherNumList:
    if i%2==1:
        OtherNumList2.append(i)
        OtherNumList2.append(i)
    else:
        OtherNumList2.append(i)
print(OtherNumList2)

I want to do this using just an expression, or otherwise "one-line" it using a list comprehension.

I'm struggling with understanding how to set the comprehension to append twice if X while appending once if Y.

I'd appreciate your help with understanding even just the concept of building the comprehension; I do not expect a spoon-fed solution, and would rather prefer it if you could walk me through your thinking process so that I can better set my own foundations for better list comprehensions in the future! :)

like image 359
Dkoded Avatar asked Mar 29 '19 14:03

Dkoded


3 Answers

You can do this in a single list comprehension with no outside tools. You just have to make and walk an inner sequence of values based on the value pulled from the outer sequence:

OtherNumList = [1, 2, 3, 8, 9]
OtherNumList2 = [rep for i in OtherNumList for rep in (i,)*(i%2+1)]
print(OtherNumList2)

The trick here is the second for. It iterates a tuple of one or two copies of i, depending on whether i is even (one copy) or odd (two copies). Conveniently, we don't even need a real boolean check here; (i%2+1) is always 1 for even and 2 for odd already so we can use it to multiply directly. The resulting value is then produced the correct number of times directly, without additional flattening required.

like image 200
ShadowRanger Avatar answered Oct 01 '22 23:10

ShadowRanger


One way could be by generating a nested list, and flattening it afterwards using for instance itertools.chain. The tricky part is creating a flat list straight away, as you'll have to append more than one element at once when the the condition is not satisfied, so you need a little extra work to flatten the resulting list:

from itertools import chain
list(chain.from_iterable([i] if i%2 == 0 else [i]*2 for i in l))

Output

[1, 1, 2, 3, 3, 8, 9, 9]

Although it would seem to me that the optimal way to do this would be with a generator function, or very similarly, the one you've shared, but possibly preferable for large lists:

def my_fun(l):
    for i in l:
        if i%2 == 0:
            yield i
        else:
            yield i
            yield i

list(my_fun(l))
# [1, 1, 2, 3, 3, 8, 9, 9]
like image 44
yatu Avatar answered Oct 02 '22 00:10

yatu


import numpy as np
num_list = [1, 2, 3, 8, 9]
new_list = []

for x in num_list:
    new_list.extend(np.repeat(x, 2, axis=0)) if x%2 == 1 else new_list.append(x)
like image 38
Emma Jean Avatar answered Oct 02 '22 00:10

Emma Jean