Iterator in not generating list correctly - python

Why this code is returning [[2, 3]] instead of [[1, 2, 3], [2, 4, 6], [3, 6, 9]] ?
i = (i for i in range(1, 4))
l = [[x * y for y in i] for x in i]
print(l)

i is generator object, which means the values in it are consumed after the first iteration. In [[x * y for y in i] for x in i] you iterate over it twice, in the seconed time its empty. You can change i to list instead
i = [i for i in range(1, 4)]
l = [[x * y for y in i] for x in i]
print(l)
# output [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

As already noted you created i which is exhaustable, I suggest different fix: just use range directly i.e:
i = range(1, 4)
l = [[x * y for y in i] for x in i]
print(l)
output:
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
call to range does create instance of class range which might be used multiple times for example
x = range(1,4)
print(list(x))
print(list(x))
print(list(x))
output:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]

Related

Multiply digits in list in python

I have a list:
lst = [[7], [4, 3, 5, 8], [1, 3]]
How can I multiply each element in list by it position like this:
[[7 * 0],[4 * 0 + 3 * 1 + 5 * 2 + 8 * 3], [1 * 0 + 3 * 1]]
And print answer:
answer = [[0], [37], [3]]
You can use a list comprehension with sum and enumerate:
L = [[7], [4, 3, 5, 8], [1, 3]]
res = [[sum(i*j for i, j in enumerate(sublist))] for sublist in L]
print(res)
[[0], [37], [3]]
Or if you are happy to use a 3rd party library, you can use NumPy:
import numpy as np
L = [[7], [4, 3, 5, 8], [1, 3]]
res = [np.arange(len(sublist)).dot(sublist) for sublist in L]
print(res)
[0, 37, 3]
This is a possible solution ...
a_list = [[7], [4, 3, 5, 8], [1, 3]]
new_list = []
for sub_list in a_list:
sublistsum = 0
for i, value in enumerate(sub_list):
sublistsum = sublistsum + i * value
new_list.append([sublistsum])
print(new_list)

How to do Math Functions on Lists within a List

I'm very new to python (using python3) and I'm trying to add numbers from one list to another list. The only problem is that the second list is a list of lists. For example:
[[1, 2, 3], [4, 5, 6]]
What I want is to, say, add 1 to each item in the first list and 2 to each item in the second, returning something like this:
[[2, 3, 4], [6, 7, 8]]
I tried this:
original_lst = [[1, 2, 3], [4, 5, 6]]
trasposition_lst = [1, 2]
new_lst = [x+y for x,y in zip(original_lst, transposition_ls)]
print(new_lst)
When I do this, I get an error
can only concatenate list (not "int") to list
This leads me to believe that I can't operate in this way on the lists as long as they are nested within another list. I want to do this operation without flattening the nested list. Is there a solution?
One approach using enumerate
Demo:
l = [[1, 2, 3], [4, 5, 6]]
print( [[j+i for j in v] for i,v in enumerate(l, 1)] )
Output:
[[2, 3, 4], [6, 7, 8]]
You can use enumerate:
l = [[1, 2, 3], [4, 5, 6]]
new_l = [[c+i for c in a] for i, a in enumerate(l, 1)]
Output:
[[2, 3, 4], [6, 7, 8]]
Why don't use numpy instead?
import numpy as np
mat = np.array([[1, 2, 3], [4, 5, 6]])
mul = np.array([1,2])
m = np.ones(mat.shape)
res = (m.T *mul).T + mat
You were very close with you original method. Just fell one step short.
Small addition
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
new_lst = [[xx + y for xx in x] for x, y in zip(original_lst, transposition_lst)]
print(new_lst)
Output
[[2, 3, 4], [6, 7, 8]]
Reasoning
If you print your original zip it is easy to see the issue. Your original zip yielded this:
In:
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
for x,y in zip(original_lst, transposition_lst):
print(x, y)
Output
[1, 2, 3] 1
[4, 5, 6] 2
Now it is easy to see that you are trying to add an integer to a list (hence the error). Which python doesn't understand. if they were both integers it would add them or if they were both lists it would combine them.
To fix this you need to do one extra step with your code to add the integer to each value in the list. Hence the addition of the extra list comprehension in the solution above.
A different approach than numpy that could work even for lists of different lengths is
lst = [[1, 2, 3], [4, 5, 6, 7]]
c = [1, 2]
res = [[l + c[i] for l in lst[i]] for i in range(len(c))]

Need to convert 3d array to 2d with mean of inner array

I am receiving a output like the below:
y = [[[1,1,1,1,1,1,1] ,[2,2,2,2,2,2,2], [3,3,3,3,3,3,3]],[[4,4,4],[5, 5, 5],[6, 6, 6]]]
the final output should be as below:
Y = [[1, 2, 3], [4, 5, 6]]
How to convert y to Y? [Here, the mean of the innermost array (or optionally any element) need to be used as a basic element and the final array (Y) need to be 2D, whereas the pre-final array (y) is 3D.
(I am new to numpy/python, so this question my look stupid, if any other information is needed, please let me know)
Try this,
result = []
for i in lst:
result.append([j[0] for j in i])
print result
Result
[[1, 2, 3], [4, 5, 6]]
With list comprehension:
y = [[[1,1,1,1,1,1,1] ,[2,2,2,2,2,2,2], [3,3,3,3,3,3,3]],[[4,4,4],[5, 5, 5],[6, 6, 6]]]
Y = [[x[0] for x in z] for z in y] # [[1, 2, 3], [4, 5, 6]]
double loops and insert will do the trick
import numpy as np
y = [[[1, 1, 1, 1, 1, 1, 1 ], [2, 2, 2, 2, 2, 2, 2 ] ,[3, 3, 3, 3, 3, 3, 3]],[[4, 4, 4],[5, 5, 5],[6, 6, 6]]]
Y = []
for l in y:
inner_l = []
for sub_l in l :
inner_l.append(np.mean(sub_l))
Y.append(inner_l)
print Y
y=[[[1,1,1,1,1,1,1] ,[2,2,2,2,2,2,2], [3,3,3,3,3,3,3]],[[4,4,4],[5, 5, 5],[6, 6, 6]]]
rslt = []
for x in y:
lst=[]
for m in x:
lst.append([m[0]])
rslt.append(lst)
Result:
rslt = [[1, 2, 3], [4, 5, 6]]

Pythonic way to generate a list of possible arrays

Given an array of numbers (e.g. [3, 5, 2]), I'm trying to generate a list of possible arrays that result from adding 1 to one entry in the array: [[4, 5, 2], [3, 6, 2], [3, 5, 3]].
I can get it done by the following, but wondering if there's a more pythonic way to get the result?
test = [3, 5, 2]
result = [t.copy() for _ in range(len(test))]
for index, _ in enumerate(result):
result[index][index] += 1
Here's how to do it with a list comprehension:
test = [3, 5, 2]
print [test[:i] + [v + 1] + test[i+1:] for i,v in enumerate(test)]
output
[[4, 5, 2], [3, 6, 2], [3, 5, 3]]
Here is another inline solution with list comprehension:
test = [3, 5, 2]
result = [[v+1 if i==j else v for j, v in enumerate(test)] for i in range(len(test))]
or, as noticed by PM 2Ring, you can exploit the fact that True == 1 and False == 0:
result = [[v + (i==j) for j, v in enumerate(test)] for i in range(len(test))]

Python : Generating cyclic permutations code (An unexpected code error to be clarified)

I didn't manage to correct a code I thought it would work for sure. Any advice to make the code functional is accepted.
Expected outputs of the following code is a list containing a cyclic permuation of the list
l = [1,2,3,4] (i.e : [[4, 1, 2, 3],[3, 4, 1, 2],[2, 3, 4, 1],[1, 2, 3, 4]])
Although what I get is : [[2, 3, 4, 1]]
The code :
def cycGen(l):
L=[]
while not(l in L) :
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
print(cycGen([1,2,3,4]))
Another variation of the solution is to consider the following code wich seems unfortunatly not working either :
def cycGen(l):
L=[]
for k in range(len(l)):
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
Help me with your generous knowlege sharing please.
You can use collections.deque:
from collections import deque
a = [1, 2, 3, 4]
d = deque(a)
for _ in range(len(a)):
d.rotate()
print(list(d))
Which gives you the output:
[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]
As mentioned in Efficient way to shift a list in python
An easy way is just:
In [12]: x = [1,2,3,4]
In [13]: [x[i:]+x[:i] for i in range(len(x))]
Out[13]: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
In your first code sample, the line L.append(l) appends a "reference" (loosely speaking) to the list l to the end of L, rather than appending a copy as you seem to be expecting. Thus, when l is later modified, the reference to it contained in L is modified as well, and so when l in L is tested, l will equal the reference to itself in L, and so the loop will end. The same basic problem causes your second code sample to return multiples of the same list rather than several different lists.
To store a copy of l at the current point in time in L instead, use L.append(l[:]).
Here is an easy way:
>>> def cycGen(l):
size = len(l)
return [[l[(i+j)%size] for i in range(size)] for j in range(size)]
>>> l = [1,2,3,4]
>>> print cycGen(l)
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
You could do this using a generator too:
a = [1, 2, 3, 4]
def next_pos(max):
i = 0
while True:
for n in xrange(max):
yield n + i
i += 1
pos = next_pos(len(a))
b = []
for i in xrange(len(a)):
n = []
for j in xrange(len(a)):
m = pos.next()
if m >= len(a):
m -= len(a)
n.append(a[m])
b.append(n)
print b
output:
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]

Categories

Resources