Rotating a list without using collection.deque - python

I want to make a script. The program should get some list L with values, and natural number N.
If N>0, the list's objects move N steps to left.
If N<0, the list's objects move abs(N) to the right.
If N=0 the list remain the same...
For example: For N=1 and L=[1,2,3,4,5], the output is [2,3,4,5,1].
For same list and N=-1 the output is [5,1,2,3,4]
I actually did it using collection.deque, but I want to do this with nothing but lists, for loop and 'if'.
I have problem to understand how to make the objects move.
l = input("enter list:")
N = input("enter number of rotations:")
import collections
d = collections.deque(l)
d.rotate(-N)
print d

You can use list slicing:
def rotate(L, N):
if not L or N % len(L) == 0:
return L
return L[N % len(L):] + L[:N % len(L)]
L = [1, 2, 3, 4, 5]
for N in range(-3, 4):
print(rotate(L, N))
Output:
[3, 4, 5, 1, 2]
[4, 5, 1, 2, 3]
[5, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[2, 3, 4, 5, 1]
[3, 4, 5, 1, 2]
[4, 5, 1, 2, 3]
Note that if you use a list, the time complexity of a rotation is linear to the number of elements in the list in general, since you have to move all existing elements. deque.rotate(), on the other hand, is O(k), with k being the number of steps. Therefore, if you need to rotate more than once deque.rotate() is the way to go.

This works:
result = l[N % len(l):]+l[:N % len(l)]

If using numpy is an option for you, there is a method called roll, which you might want to have a look at:
import numpy as np
array = np.arange(1, 6) # 1 to 5
print array
print np.roll(array, 0)
print np.roll(array, 2)
print np.roll(array, -2)
print np.roll(array, 17)
The result is as expected:
[1 2 3 4 5]
[1 2 3 4 5]
[4 5 1 2 3]
[3 4 5 1 2]
[4 5 1 2 3]

If you're after simple lists here's how you can do it in Python 3 (based on your P2 example).
L = list(map(int, input("Enter numbers: ").split(" ")))
N = int(input("Enter how many rotations to perform: "))
print(L[N:] + L[:N])

If you don't want to create new list, you can try in-place reverse,
def reverse(nums, start, end):
i = start
j = end - 1
while i < j:
tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
i += 1
j -= 1
def rotate(nums, n):
if n == 0:
return nums
length = len(nums)
if n < 0:
n = length + n
reverse(nums, 0, n)
reverse(nums, n, length)
reverse(nums, 0, length)
return nums
>>> rotate([1, 2, 3, 4, 5], 1)
[2, 3, 4, 5, 1]
>>> rotate([1, 2, 3, 4, 5], -1)
[5, 1, 2, 3, 4]

thank you all ! :)
your answers are great and very useful for me.
here is my solution for this question (given that I do these scripts for a basic python course for biologists):
L = input('Enter list of numbers, please: ')
N = input('Enter how many places to rotate: ')
L1 = L[N:]
L2 = L[:N]
L = L1 + L2
print L

Related

Find the sum of two arrays

I am trying to find the sum of two lists/arrays in Python.
For example:
You are given with two random integer lists as lst1 and lst2 with size n and m respectively. Both the lists contain numbers from 0 to 9(i.e. single digit integer is present at every index).
The idea here is to represent each list as an integer in itself of digits N and M.
You need to find the sum of both the input list treating them as two integers and put the result in another list i.e. output list will also contain only single digit at every index.
Following is the code which I have tried:
def list_sum(lst1, n, lst2, m) :
i, j, sum, carry = 0, 0, 0, 0
new_lst = []
if n == 0 and m == 0:
new_lst.append(0)
elif n > 0 and m>0:
while n > 0 and m > 0:
sum = lst1[n - 1] + lst2[m - 1] + carry
if sum >= 10:
carry = 1
else:
carry = 0
new_lst.append(sum % 10)
n -= 1
m -= 1
while n > 0:
if (lst1[n-1] + carry) >= 10:
new_lst.append((lst1[n-1] + carry) % 10)
carry = 1
else:
new_lst.append(lst1[n-1])
carry = 0
n -= 1
while m > 0:
if (lst2[m-1] + carry) >= 10:
new_lst.append((lst2[m-1] + carry) % 10)
carry = 1
else:
new_lst.append(lst1[m-1])
carry = 0
m -= 1
if carry == 1:
new_lst.append(1)
new_lst.reverse()
elif n == 0 and m > 0:
new_lst.append(0)
new_lst = new_lst + lst2
elif n > 0 and m == 0:
new_lst.append(0)
new_lst = new_lst + lst1
print(new_lst)
however I feel I am missing something here and which is not giving me proper answer for the combination. Sometimes it errors list out of index error. I don't know why.
The example input:
n = 3
lst1 = [6, 9, 8]
m = 3
lst2 = [5, 9, 2]
output:
[1, 2, 9, 0]
Here, each element is summed and then if the sum >=10 then we get a carry = 1 and which will be added with the next sum.
i.e
1. 8+2= 10 >=10 hence carry=1 in first sum
2. 9+9+1( carry) = 19 >=10 hence carry=1
3. 6+5+1( carry) = 12>=10 hence carry=1
4. upend the carry to next position as 1
Hence resultant list would be [1, 2, 9, 0]
What can I try next?
Well, all other answers are awesome for adding 2 numbers (list of digits).
But in case you want to create a program which can deal with any number of 'numbers',
Here's what you can do...
def addNums(lst1, lst2, *args):
numsIters = [iter(num[::-1]) for num in [lst1, lst2] + list(args)] # make the iterators for each list
carry, final = 0, [] # Initially carry is 0, 'final' will store the result
while True:
nums = [next(num, None) for num in numsIters] # for every num in numIters, get the next element if exists, else None
if all(nxt is None for nxt in nums): break # If all numIters returned None, it means all numbers have exhausted, hence break from the loop
nums = [(0 if num is None else num) for num in nums] # Convert all 'None' to '0'
digit = sum(nums) + carry # Sum up all digits and carry
final.append(digit % 10) # Insert the 'ones' digit of result into final list
carry = digit // 10 # get the 'tens' digit and update it to carry
if carry: final.append(carry) # If carry is non-zero, insert it
return final[::-1] # return the fully generated final list
print(addNums([6, 9, 8], [5, 9, 2])) # [1, 2, 9, 0]
print(addNums([7, 6, 9, 8, 8], [5, 9, 2], [3, 5, 1, 7, 4])) # [1, 1, 2, 7, 5, 4]
Hope that makes sense!
If I understand correctly you want it like this:
[6, 9, 8], [5, 9, 2] -> 698 + 592 = 1290 -> [1, 2, 9, 0]
In that case my first idea would be to turn the numbers into strings, combine them to one string
and turn it into an int, then add both values together and turn into a list of integers again...
you can try this:
def get_sum_as_list(list1, list2):
first_int = int(''.join(map(str,list1)))
second_int = int(''.join(map(str,list2)))
result = [int(num) for num in str(first_int+second_int)]
return result
Here's one possible solution:
(i) join each list to create a pair of string representation of integers
(ii) convert them to integers,
(iii) add them,
(iv) convert the sum to string
(v) separate each digit as ints
def list_sum(lst1, lst2):
out = []
for i, lst in enumerate([lst1, lst2]):
if len(lst) > 0:
out.append(int(''.join(str(x) for x in lst)))
else:
if i == 0:
return lst2
else:
return lst1
return [int(x) for x in str(out[0]+out[1])]
list_sum([6,9,8],[5,9,2])
Output:
[1, 2, 9, 0]
Two other answers show solutions repeatedly converting between lists of int and strings and ints. I think this is a bit cheating and completely hides the algorithm.
Here I present a solution that manipulates the lists of ints directly to build a third list of ints.
from itertools import chain, repeat # pad list with 0 so they are equal size
from operator import add # add(x,y) = x+y
def padded(l1, l2):
"padded([1, 2, 3], [1, 2, 3, 4, 5]) --> [0, 0, 1, 2, 3], [1, 2, 3, 4, 5]"
padded1 = chain( repeat(0, max(0, len(l2)-len(l1))), l1 )
padded2 = chain( repeat(0, max(0, len(l1)-len(l2))), l2 )
return padded1, padded2
def add_without_carry_same_size(l1, l2):
"add_without_carry([6, 9, 8], [5, 9, 2]) --> [11, 18, 10]"
return map(add, l1, l2)
def flatten_carry(l):
"flatten_carry([11, 18, 10]) --> [1, 2, 9, 0]"
c = 0
for i in range(len(l)-1, -1, -1):
c, l[i] = divmod(c + l[i], 10)
if c > 0:
l[:] = [c] + l
def list_add(l1, l2):
'''
list_add([6, 9, 8], [5, 9, 2]) --> [1, 2, 9, 0]
list_add([9, 9, 9, 9, 9], [1]) --> [1, 0, 0, 0, 0, 0]
'''
p1, p2 = padded(l1, l2)
l3 = list(add_without_carry_same_size(p1, p2))
flatten_carry(l3)
return l3
Relevant documentation:
builtin function map;
itertools.chain;
itertools.repeat;
operator.add;
builtin function divmod.
Tried the following logic
def list_sum(lst1, n, lst2, m, output):
i, j, k, carry = n - 1, m - 1, max(n, m), 0
while i >= 0 and j >= 0:
output[k] = (lst1[i] + lst2[j] + carry) % 10
carry = (lst1[i] + lst2[j] + carry) // 10
i = i - 1
j = j - 1
k = k - 1
while i >= 0:
output[k] = (lst1[i] + carry) % 10
carry = (lst1[i] + carry) // 10
i = i - 1
k = k - 1
while j >= 0:
output[k] = (lst2[j] + carry) % 10
carry = (lst2[j] + carry) // 10
j = j - 1
k = k - 1
output[0] = carry
print(output)
where the output parameter in the above code it taken from below
outputSize = (1 + max(n, m))
output = outputSize * [0]
and called the function
list_sum(lst1, n, lst2, m, output)
You don't mention how long your lists will be. So considering they aren't going to be that long (anyway, python can handle bignums), why not making a simple sum operation? In the end that's what the code should emulate.
import numpy as np
lst1 = [6, 9, 8]
lst2 = [5, 9, 2]
lst1_len = len(lst1)
lst2_len = len(lst2)
if lst1_len >= lst2_len:
lst2 = [0] * (lst1_len - lst2_len) + lst2
else:
lst1 = [0] * (lst2_len - lst1_len) + lst1
common_len = len(lst1)
lst1_val = sum(np.array(lst1) * np.array([10**(-x) for x in range(-common_len + 1, 1)]))
lst2_val = sum(np.array(lst2) * np.array([10**(-x) for x in range(-common_len + 1, 1)]))
total = lst1_val + lst2_val
total_as_list = [int(x) for x in str(total)]
where
print(total_as_list)
[1, 2, 9, 0]
Code:
def addNums(*args):
nums=[]
for i in args:
if i:
i = list(map(str,i)) # Converts each element int to string['6', '9', '8'] , ['5', '9', '2']
add=int(''.join(i)) # Joins string and convert to int 698 ,592
nums.append(add) # Appends them to list [698, 592]
Sum = str(sum(nums)) # Sums the values and convert to string '1290'
result=list(map(int,Sum)) # Converts to list with each converted to int[1,2,9,0]
return result
print(addNums([6, 9, 8], [5, 9, 2]))
print(addNums([7, 6], [5, 9], [3, 5],[7, 4]))
print(addNums([]))
Output:
[1, 2, 9, 0]
[2, 4, 4]
[0]

How to shift items in an array by a "K" number of times?

Shift the items in the given array, by some number of times, as shown in the below examples;
array = [1, 2 ,3 , 4, 5, 6]
k1 = 2
k2 = -3
k3 = 20
test1:
cirShift(array, k1)
Result: [5, 6, 1, 2, 3, 4]
test2:
cirShift(array, k2)
Result: [4, 5, 6, 1, 2, 3]
test3:
cirShift(array, k3)
Result: [5, 6, 1, 2, 3, 4]
I have used the below to achieve the right-rotate a list by k positions;
def rightRotateByOne(A):
Fin= A[-1]
for i in reversed(range(len(A) - 1)):
A[i + 1] = A[i]
A[0] = Fin
def rightRotate(A, k):
if k < 0 or k >= len(A):
return
for i in range(k):
rightRotateByOne(A)
if __name__ == '__main__':
A = [1, 2, 3, 4, 5, 6, 7]
k = 3
rightRotate(A, k)
print(A)
As of now, able to obtain results for test1 but would like to achieve the test2 and test3
Even easier, split the array in half given the boundary, swap and glue back:
def cirShift(a, shift):
if not shift or not a:
return a
return a[-shift%len(a):] + a[:-shift%len(a)]
Courtesy of #KellyBundy, a short-circut one-liner:
def cirShift(a, shift):
return a and a[-shift%len(a):] + a[:-shift%len(a)]
I think this question may be an exercise in self learning ('how to do X using just python'), so my answer is auxiliary, but you can always use np.roll():
#test 1
import numpy as np
a = [1, 2 ,3, 4, 5, 6]
np.roll(a, 2)
gives output
[5, 6, 1, 2, 3, 4]
and
#test 2
np.roll(a, -2)
gives output
[3, 4, 5, 6, 1, 2]
Even if you give a number that is larger than the array size, it handles the overflow:
#test 3
np.roll(a, 10)
gives output
[3, 4, 5, 6, 1, 2]
Rolling also works in multiple dimension arrays and across specified axes, which is pretty neat.
def shift(l, shift_t):
r = [*l]
for n in range(abs(shift_t)):
if shift_t < 0:
r = r[1:] + [r[0]]
else:
r = [r[-1]] + r[:-1]
return r
The key is to take one item of the list and place it on the opposite side, which is essentially all that shifting is doing. If you shift negative, you put the first one at the end, and if you shift positive, you put the last one at the beginning.

Repeat values in array until specific length [duplicate]

This question already has answers here:
How to replicate array to specific length array
(4 answers)
Closed 2 years ago.
I need some kind of function or little tip for my problem.
So I got a list let's say
[1,2,3,4]
but I need this array to be longer with the same elements repeated so let's say I need an array of length 10 so it becomes:
[1,2,3,4,1,2,3,4,1,2]
So I need to extend the list with the same values as in the list in the same order
returnString = the array or string to return with extended elements
array = the basic array which needs to be extended
length = desired length
EDIT:
returnString = ""
array = list(array)
index = 0
while len(str(array)) != length:
if index <= length:
returnString += array[index]
index += 1
else:
toPut = index % length
returnString.append(array[toPut])
index += 1
return returnString
This is simple with itertools.cycle and itertools.islice:
from itertools import cycle, islice
input = [1, 2, 3, 4]
output = list(islice(cycle(input), 10))
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
You can use itertools.cycle to iterate repeatedly over the list, and take as many values as you want.
from itertools import cycle
lst = [1, 2, 3, 4]
myiter = cycle(lst)
print([next(myiter) for _ in range(10)])
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
You can also use it to extend the list (it doesn't matter if you append to the end while you are iterating over it, although removing items would not work).
from itertools import cycle
lst = [1, 2, 3, 4]
myiter = cycle(lst)
for _ in range(6):
lst.append(next(myiter))
print(lst)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
One way could be:
Iterate over the desired length - len(x_lst), So you have 10 - 4 = 6 (new elements to be added). Now since the list element should repeat, you can append the x_lst elements on the go by the indices (0,1,2,3,4,5).
x = [1,2,3,4]
length = 10
for i in range(length - len(x)):
x.append(x[i])
print(x)
OUTPUT:
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
Try this:
n = 10
lst =[1,2,3,4]
new_lst = [lst[i%len(lst)] for i in range(n)]
print(new_lst)
Output:
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
I will show a tip to you:
If you have this array [1,2,3,4] so you can create a separated newArray that get this value and fill the newArray with this repeated values.
How? Loop! I think for can do this to you, just point the array and newArray to it knows which it will fill.
NumOfValues = int(input("Number of Values: "))
List1 = [1,2,3,4]
List2 = []
Count = 0
while len(List2) < NumOfValues:
List2.append(List1[Count])
Count += 1
if Count > len(List1) - 1:
Count = 0
print(List2)
First multiply the list by the number of times it needs to be repeated. If that's not the desired length, extend it with the appropriate slice of the list.
old_len = len(original)
new_len = 10
result = original * new_len // old_len
if new_len % old_len != 0:
result += original[:new_len % old_len]

Combining array elements in a particular way, and recording it

I am given a 1D array of numbers.
I need to go through the array adding each consecutive element to form a sum. Once this sum reaches a certain value, it forms the first element of a new array. The sum is then reset and the process repeats, thus iterating over the whole array.
For example if given:
[1, 3, 4, 5, 2, 5, 3]
and requiring the minimum sum to be 5,
the new array would be:
[8, 5, 7]
Explicity: [1 + 3 + 4, 5, 2 + 5]
I then also need to keep a record of the way the elements were combined for that particular array: I need to be to take a different array of the same length and combine the elements in the same way as above.
e.g. give the array
[1, 2, 1, 1, 3, 2, 1]
I require the output
[4, 1, 5]
Explicity: [1 + 2 + 1, 1, 3 + 2]
I have accomplished this with i loops and increment counters, but it is very ugly. The array named "record" contains the number of old elements summed to make each element of the new array i.e. [3, 1, 2]
import numpy as np
def bin(array, min_sum):
num_points = len(array)
# Create empty output.
output = list()
record = list()
i = 0
while i < num_points:
sum = 0
j = 0
while sum < min_sum:
# Break out if it reaches end of data whilst in loop.
if i+j == num_points:
break
sum += array[i+j]
j += 1
output.append(sum)
record.append(j)
i += j
# The final data point does not reach the min sum.
del output[-1]
return output
if __name__ == "__main__":
array = [1, 3, 4, 5, 2, 5, 3]
print bin(array, 5)
I would advice you to simply walk through the list. Add it to an accumulator like the_sum (do not use sum, since it is a builtin), and in case the_sum reaches a number higher than the min_sum, you add it, and reset the_sum to zero. Like:
def bin(array, min_sum):
result = []
the_sum = 0
for elem in array:
the_sum += elem
if the_sum >= min_sum:
result.append(the_sum)
the_sum = 0
return result
The lines where the accumulator is involved, are put in boldface.
I leave combining the other array the same way as an exercise, but as a hint: use an additional accumulator and zip to iterate over both arrays concurrently.
Here is a straightforward solution. which computes a list of boolean values where the value is true when accumulated element equals or exceeds the target value and calc computes an accumulation using this list.
def which(l, s):
w, a = [], 0
for e in l:
a += e
c = (a >= s)
w.append(c)
if c:
a = 0
return w
def calc(l, w):
a = 0
for (e, c) in zip(l, w):
a += e
if c:
yield a
a = 0
here is an interactive demonstration
>>> l1 = [1, 3, 4, 5, 2, 5, 3]
>>> w = which(l1, 5)
>>> w
[False, False, True, True, False, True, False]
>>> list(calc(l1, w))
[8, 5, 7]
>>> l2 = [1, 2, 1, 1, 3, 2, 1]
>>> list(calc(l2, w))
[4, 1, 5]
You can use short solutions I found out after a long struggle with flattening arrays.
For getting bounded sums use:
f = lambda a,x,j,l: 0 if j>=l else [a[i] for i in range(j,l) if sum(a[j:i])<x]
This outputs:
>>> f = lambda a,x,j,l: 0 if j>=l else [a[i] for i in range(j,l) if sum(a[j:i])< x]
>>> a= [1, 3, 4, 5, 2, 5, 3]
>>> f(a,5,0,7)
[1, 3, 4]
>>> sum(f(a,5,0,7))
8
>>> sum(f(a,5,3,7))
5
>>> sum(f(a,5,4,7))
7
>>>
To get your records use the function:
>>> y = lambda a,x,f,j,l: [] if j>=l else list(np.append(j,np.array(y(a,x,f,j+len(f(a,x,j,l)),l))))
From here, you can get both array of records and sums:
>>> listt=y(a,5,f,0,len(a))
>>> listt
[0.0, 3.0, 4.0, 6.0]
>>> [sum(f(a,5,int(listt[u]),len(a))) for u in range(0,len(listt)-1)]
[8, 5, 7]
>>>
Now, the bit of magic you can even use it as an index-conditional boundary for the second vector:
>>> b=[1, 2, 1, 1, 3, 2, 1]
>>> [sum(f(b,5,int(listt[u]),int(listt[u+1]))) for u in range(0,len(listt)-1)]
[4, 1, 5]
>>>

List comprehension with for loop

How can I double the first n odd numbers in a list using list comprehension?
Here is my solution:
>>> n = 2
>>> lst = [1, 2, 3, 4, 5, 6]
>>> lst = [num for num in lst if num % 2 == 1] + [num for num in lst if num % 2 == 0]
>>> lst = [num * 2 for num in lst[:n]] + lst[n:]
>>> print(lst)
[2, 6, 5, 2, 4, 6]
You can see that I can't keep the same order of lst anymore...
More example:
n = 2
lst = [2, 2, 2, 2, 1, 2, 3]
output: lst = [2, 2, 2, 2, 2, 2, 6]
Solution for the original requirement to *“double the first n numbers in a list if it’s odd”:
Since you do not want to remove any items from your original list, you cannot use the filter of the list comprehension syntax (the if after the for). So what you need to do instead is simply transform the item you are putting into the target list.
Your logic is something like this for an element x at index i:
def transform(x, i, n):
if i < n:
if x % 2 == 1:
return x * 2
return x
So you can use that exact function and use it in your list comprehension:
>>> n = 2
>>> lst = [1, 2, 3, 4, 5, 6]
>>> [transform(x, i, n) for i, x in enumerate(lst)]
[2, 2, 3, 4, 5, 6]
And of course, you can put this also inline into the list comprehension:
>>> [x * 2 if i < n and x % 2 == 1 else x for i, x in enumerate(lst)]
[2, 2, 3, 4, 5, 6]
First n odd numbers:
If you want to find the first n odd numbers, you cannot solve this like this. In order to solve this, you need to actually remember how many odd numbers you encountered before while going through the list. This means that you need to have some kind of “memory”. Such a thing is not a good fit for a list comprehension since list comprehensions are supposed to transform one item at a time without having side effects.
So instead, you would simply do this the straightforward way:
n = 2
lst = [2, 2, 2, 2, 1, 2, 3]
result = []
for x in lst:
if x % 2 == 1 and n > 0:
result.append(x * 2)
n -= 1
else:
result.append(x)
print(result) # [2, 2, 2, 2, 2, 2, 6]
For this to work, you'll need to keep count of odd numbers that you've already seen. For example, you could instantiate the itertools.count generator and advance it each time the odd number is encountered:
from itertools import count
def f(l, n):
odd = count()
return [x * 2 if x % 2 and next(odd) < n else x for x in l]
>>> f([1, 2, 3, 4, 5, 6], 2)
[2, 2, 6, 4, 5, 6]
>>> f([2, 2, 2, 2, 1, 2, 3], 2)
[2, 2, 2, 2, 2, 2, 6]
Use the ternary operator.
lst = [1, 2, 3, 4, 5, 6]
lst = [x * 2 if x % 2 == 1 and i <= n else x for i, x in enumerate(lst)]
or
lst[:n] = [x * 2 if x % 2 == 1 else x for x in lst[:n]]
Update: Under the new requirement of doubling first n odd integers:
lst = [1, 2, 3, 4, 5, 6]
class Doubler:
def __init__(self, n):
self.n = n
def proc(self, x):
if self.n > 0 and x % 2:
self.n -= 1
return 2 * x
return x
# Double first 2 odd elements
d = Doubler(n=2)
res = [d.proc(x) for x in lst]
print(res)
# [2, 2, 6, 4, 5, 6]
Name things with specificity, and the logic is exposed.
How can I double the first n odd numbers in a list using list comprehension?
We have odd numbers: v for v in l if n%2. This is a filter.
We can take the first n of them using islice(odds, n). We call this a slice, other languages might call it "take". And doubling them is a per item operation, so a map. Join these operations and we arrive at one answer to your question:
[v*2 for v in islice((v for v in l if n%2), n)]
However, that isn't what you wanted. The issue is specificity; your question doesn't say what to do with other items than the first n odd ones, so I have just ignored them.
So what do do if we want a replication of all the items your question did not mention? This means we have three groups: early odds, late odds, and evens, all processed distinctly. The latter may be mixed in arbitrarily, while we know late odds come after early odds. It's impractical to split them in individual streams, as you've shown, since that doesn't preserve their relative order.
I'll apply a few more itertools functions to solve this problem.
from itertools import repeat, chain
oddfactors = chain(repeat(2, n), repeat(1))
outlist = [v*next(oddfactors) if v%2 else v
for v in inlist]
Note that the iterator oddfactors is read for each odd item, not even items, because the if-else expression doesn't evaluate the expression if it's not being used. The iterator is consumed and you need to create another to perform the work again.
It is possible to place the oddfactors iterator's creation (and entire scope) within the list comprehension, but the first way I can think of is incredibly ugly:
from itertools import repeat, chain
outlist = [v*next(oddfactors) if v%2 else v
for v,oddfactors in zip(
inlist,
repeat(chain(repeat(2, n), repeat(1)))
)]
The trick here is to ensure we create the chained iterator only once, then feed it into each mapping operation. This exercise sure didn't help readability or performance. Using a nested comprehension would make it a bit cleaner but there's still only the one iterator, so it's a misleading hack.
outlist = [v*next(oddfactors) if v%2 else v
for oddfactors in [chain(repeat(2, n), repeat(1))]
for v in inlist]
How about this?
n = 2
lst = [1, 2, 3, 4, 5, 6]
for i in range(n):
lst[i]= lst[i]*2
[num if num%2 else 2*num for num in list]. num if a if b else c will return a if b is true, otherwise c.

Categories

Resources