something unexpected in python when i design a nested list - python-3.x

i want to turn 'a' to a nested list:
so i design a while loop:
a = [1,2,3,4,5,6,7,8,9,10,11,12]
ll = l = []
m,f,k = 1,0,4
while m <= 3:
l.append(a[int(f):int(k)])
f = f + 4
k = k + 4
ll.append(l)
m = m+1
print(ll)
i want [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]] rather than[[1, 2, 3, 4], [...], [5, 6, 7, 8], [...], [9, 10, 11, 12], [...]]
why the result contains [...]
where is the problem in while loop

Lists are mutable objects, so ll=l=[] means that ll is the
exact same object as l. This can be verified using the is operator:
>>> ll is l
True
This can be demonstrated as follows:
>>> a=b=[]
>>> a
[]
>>> b
[]
>>> a.append(1)
>>> a
[1]
>>> b # For all practical purposes, a is identical to b
[1]
>>> a is b
True
Therefore, the line ll.append(l) creates a recursive object!
Using the pprint module after running the above code states this clearly:
>>> # Run the posted code
>>> import pprint
>>> pprint.pprint(ll)
[[1, 2, 3, 4],
<Recursion on list with id=2032187430600>,
[5, 6, 7, 8],
<Recursion on list with id=2032187430600>,
[9, 10, 11, 12],
<Recursion on list with id=2032187430600>]
The ll list isn't actually necessary, since the l.append method already
appends the newly generated list to the l object and creates a 2D list:
>>> q=[[1,2,3,4]]
>>> q.append([5,6,7,8])
>>> q
[[1, 2, 3, 4], [5, 6, 7, 8]]
The code can be rewritten as follows:
a = [1,2,3,4,5,6,7,8,9,10,11,12]
l = list()
f,k = 0,4
# range(1,4) iterates m through the values [1, 2, 3]
# This includes the first but excludes the last
for m in range(1,4):
# f and k are already integers, so no need for typecasting
# This append statement will append the 1D slice as a single unit
l.append(a[f:k])
# a += 1 is the same as a = a + 1 but is more compact
f += 4
k += 4
print(l)
# Will be [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
If you really need to create two separate empty lists, it is better to do it this way:
>>> q=list()
>>> w=list()
>>> q is w
False

Related

How to append item to match the length of two list in Python

I am working on a Python script which is connected to a server. Every x min, server returns two list but the length of these list is not same. For ex:
a = [8, 10, 1, 34]
b = [4, 6, 8]
As you can see above that a is of length 4 and b is of length 3. Similarly, sometimes it returns
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
I have to write a logic where I have to check if length of these two list is not same, then add the 0 at the end of the list which is smaller than other list. So for ex, if input is:
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
then output will be:
a = [3, 6, 4, 5, 0, 0]
b = [8, 3, 5, 2, 9, 3]
What can I try to achieve this?
def pad(list1, list2):
# make copies of the existing lists so that original lists remain intact
list1_copy = list1.copy()
list2_copy = list2.copy()
len_list1 = len(list1_copy)
len_list2 = len(list2_copy)
# find the difference in the element count between the two lists
diff = abs(len_list1 - len_list2)
# add `diff` number of elements to the end of the list
if len_list1 < len_list2:
list1_copy += [0] * diff
elif len_list1 > len_list2:
list2_copy += [0] * diff
return list1_copy, list2_copy
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
# prints: ([3, 6, 4, 5, 0, 0], [8, 3, 5, 2, 9, 3])
print(pad(a, b))
a = [8, 10, 1, 34]
b = [4, 6, 8]
# prints: ([8, 10, 1, 34], [4, 6, 8, 0])
print(pad(a, b))
For now, I can suggest this solution:
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
# Gets the size of a and b.
sizeA, sizeB = len(a), len(b)
# Constructs the zeros...
zeros = [0 for _ in range(abs(sizeA-sizeB))]
# Determines whether a or b needs to be appended with 0,0,0,0...
if sizeA < sizeB:
a += zeros
else:
b += zeros
print(a,b)
You should use extend instead of append. This is the way to add a list to another list in Python. The list here is the list of zeros.
a = [3, 6, 4, 5, 9, 3]
b = [8, 3, 5, 2]
lenA, lenB = len(a), len(b)
diff=abs(len(a)-len(b))
if lenA < lenB:
a.extend([0]*diff)
else:
b.extend([0]*diff)
print(a)
print(b)
You could also try to use more_itertools padded() method:
It's prob. more elegant and adaptable for future Use cases.
Notes: just need to do pip install more_itertools first.
# simple example to demo it:
from more_itertools import padded
print(list(padded([1, 2, 3], 0, 5))) # last num: 5 is the numbers of 0 to be padded to make the total length to be 5. (needs 2 zeros)
# [1, 2, 3, 0, 0]
# more examples:
>>> L = [1, 2, 3]
>>> K = [3, 4, 5, 6, 8, 9]
>>> gap = len(K) - len(L)
# 3
# shorter list is L
>>>list(padded(L, 0, len(L) + gap))
[1, 2, 3, 0, 0, 0]

how to get just the value of a list in another list?

Suppose I have a two lists:
a = [1,2,3,4,5]
b = [float]
My requirement is to just get the value of the 'a' list in 'b', i.e.
b = [1,2,3,4,5, float]
So, if we either append of insert, that will again create list of list, which I don't want.
Any suggestions
Assume your input is:
a = [1,2,3,4,5]
b = ['float']
b{:] = a+b
print (b)
The output of this will be:
[1, 2, 3, 4, 5, 'float']
If your input is:
a = [1,2,3,4,5]
b = [float]
then your output will be:
[1, 2, 3, 4, 5, <class 'float'>]
this may be a bit clumsy, but it does what you want:
a = [1, 2, 3, 4, 5]
b = ["float"]
print(id(b))
for n in reversed(a):
b.insert(0, n)
print(b) # [1, 2, 3, 4, 5, 'float']
print(id(b))
note that the id does not change - no new list is created.
slice-assignment would also work:
b0 = b[0]
b[:len(a)] = a
b.append(b0)
if you don't mind working with a deque instead of a list you could also do this:
from collections import deque
a = [1, 2, 3, 4, 5]
b = deque(["float"])
b.extendleft(reversed(a)) # deque([1, 2, 3, 4, 5, 'float'])
you can use:
a.__add__(b)
output:
[1, 2, 3, 4, 5, <class 'float'>]

How to use list comprehensions for this?

I want to take input of 2 numbers: the number of rows and the number of columns. I then want to use these to output a matrix numbered sequentially. I want to do this using a list comprehension. The following is a possible output.
>>>> my_matrix = matrix_fill(3, 4)
>>>> my_matrix
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
I am using the following code to output a sequentially numbered list:
def matrix_fill(num_rows, num_col):
list=[i for i in range(num_col)]
return (list)
I cannot, however, figure out how to make the sequential list of numbers break into the separate lists as shown in the output based on num_rows.
I don't think you need itertools for that. The range function can take a step as a parameter. Like this:
def matrix_fill(rows,cols):
return [[x for x in range(1,rows*cols+1)][i:i+cols] for i in range(0,rows*cols,cols)]
And then it works as expected.
>>> matrix_fill(3,4)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
Let's break this down a little bit and understand what's happening.
>>> [x for x in range(1,3*4+1)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
So what we want to do is to get a new slice every four elements.
>>> [x for x in range(1,3*4+1)][0:4]
[1, 2, 3, 4]
>>> [x for x in range(1,3*4+1)][4:8]
[5, 6, 7, 8]
>>> [x for x in range(1,3*4+1)][8:12]
[9, 10, 11, 12]
So we want to iterate over the elements of the list[x for x in range(1,3*4+1)] of length "rows*cols" ( 3 * 4 ), create a new slice every "cols" number of elements, and group these slices under a single list. Therefore, [[x for x in range(1,rows*cols+1)][i:i+cols] for i in range(0,rows*cols,cols)] is a suitable expression.
Nest a list comprehension inside another one, use itertools.count() to generate the sequence:
import itertools
rows = 3
cols = 4
count_gen = itertools.count() # pass start=1 if you need the sequence to start at 1
my_matrix = [[next(count_gen) for c in range(cols)] for r in range(rows)]
print(my_matrix)
# prints: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
# As a function
def matrix_fill(rows, cols):
count_gen = itertools.count()
return [[next(count_gen) for c in range(cols)] for r in range(rows)]
If you used the numpy module, the method is extremely simple, with no list comprehension needed.
my_matrix = np.arange(1, 13).reshape(3,4)
Printing the variable my_matrix shows
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]

sort() in python does not completely work as expected

If l is a list, say [9,3,4,1,6], I know that l.sort() will sort the list in place. I also know that m=sorted(l) will create a new list, m, as a sorted version of l.
What I don't understand is why m=l.sort(), does not create m as a sorted version of l, since this appears to be an assignment of a sorted list to m. The problem can be seen from the following
In [37]: l = [9,3,4,1,6]
In [38]: m=l.sort()
In [39]: m
In [40]: type(m)
Out[40]: NoneType
Of course if I do the following, m becomes a sorted version of l
In [41]: l = [9,3,4,1,6]
In [42]: l.sort()
In [43]: m=l
In [44]: m
Out[44]: [1, 3, 4, 6, 9]
Can someone explain why m=l.sort() doesn't work as an assignment?
list.sort mutates your list to sort it, it does not return a new one.
l = [9, 3, 4, 1, 6]
l.sort()
l # [1, 3, 4, 6, 9]
If you want to create a new sorted list, use sorted.
l = [9, 3, 4, 1, 6]
m = sorted(l)
l # [9, 3, 4, 1, 6]
m # [1, 3, 4, 6, 9]
l.sort() has no return value (see here), so when you do
m = l.sort()
you're assigning m to nothing
sort() works directly on the list and has a None return type.
So, if you want to assign it to some variable and keep the original list, you can do it the following way:
l = [9,3,4,1,6]
m = sorted(l)
print(m)
Output:
[1, 3, 4, 6, 9]
It will keep the original list as it is.

using for loop with in a for loop

For a given array v=[1,2,3] I am trying to print the sum of the product of each element with s for a range of s
import numpy as np
v=[1,2,3]
for s in range(0,5):
for i in range (0,3):
tot= np.multiply(v[i],s)
b.append(tot)
print (b)
my output is
[0, 0, 0, 1, 2, 3, 2, 4, 6, 3, 6, 9, 4, 8, 12]
I am trying to get the out put as
[[0, 0, 0], [1, 2, 3], [2, 4, 6], [3, 6, 9], [4, 8, 12]]
I am not quite sure how the second for loop is working inside the first for loop. If someone can explain that, it would be wonderful.
You'd create a new list for each iteration of the outer for loop:
v=[1,2,3]
b = []
for s in range(0,5):
result = []
for i in range (0,3):
tot= np.multiply(v[i],s)
result.append(tot)
b.append(result)
print (b)
You could just use * to multiply values, and you can iterate directly over v (no need to use a range)`:
v = [1, 2, 3]
b = []
for s in range(5):
result = []
for i in v:
result.append(i * s)
b.append(result)
You can replace both loops with list comprehensions:
b = [[i * s for i in v] for s in range(5)]
import numpy as np
v=np.array([1,2,3])
b=[]
for s in range(0,5):
b.append(list(v*s))
print (b)
Should do what you want. Don't forget numpy's extremely powerful broadcasting capability.
v=[1,2,3]
b=[]
for s in range(0,5):
b.append([])
for i in range (0,3):
tot= np.multiply(v[i],s)
b[s].append(tot)
print(b)

Resources