Strings and Nested For Loops in Python - python

I have a problem where I want to have a nested for loop concatenate a string. For some reason I'm not getting the correct output. Can someone give me some advice? This should be simple.
newRow = []
matrix = []
for i in range(0,3):
for j in range(0,5):
newRow.append(j)
matrix.append(newRow)
print matrix
python test.py
[[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4]]
I want it to print...
[[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]

You keep adding to the same newRow. If you want to get a clean row, you need to create an empty one on each iteration:
matrix = [] newRow = [] <- the same array
for i in range(0,3): matrix = []
newRow = [] <- a new array for i in range(0,3):
for j in range(0,5): instead of for j in range(0,5):
newRow.append(j) newRow.append(j)
matrix.append(newRow) matrix.append(newRow)
There are, of course, more pythonic ways of achieving this, but I'm trying to point out what the problem with the code is.

You can make this if you want nested loop:
matrix = [ [ i for i in range(5)] for j in range(3)]
print matrix
[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]

matrix = []
for i in range(0,3):
matrix.append(list(range(0, 5)))
or even:
matrix = [list(range(0, 5)) for i in range(0, 3)]

You are close, its just a matter of properly scoping:
matrix = []
for i in range(0,3):
newRow = []
for j in range(0,5):
newRow.append(j)
matrix.append(newRow)
print matrix

Whatever you do,
DON'T DO THIS
DON'T DO THIS
DON'T DO THIS:
>>> x = [range(0,5)]*3
>>> x
[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
>>> x[0][0] = 'LOL'
>>> x
[['LOL', 1, 2, 3, 4], ['LOL', 1, 2, 3, 4], ['LOL', 1, 2, 3, 4]]
use a list comprehension.

Related

Python list to range

I have the list
lst = [3, 5]
How to get a range for each item in the list like this ?
[0, 1, 2, 3]
[0, 1, 2, 3, 4, 5]
This is loop is obviously not working
for i in range(0, lst):
print(i)
lst = [3, 5]
[list(range(x+1)) for x in lst]
#[[0, 1, 2, 3], [0, 1, 2, 3, 4, 5]]
Or simply:
for x in lst:
print(list(range(x+1)))
[0, 1, 2, 3]
[0, 1, 2, 3, 4, 5]
Call range() for each end; to include the end in the range, add 1:
>>> lst = [3, 5]
[3, 5]
>>> ranges = [range(end + 1) for end in lst]
[range(0, 4), range(0, 6)]
>>> for x in ranges:
... print(list(x))
...
[0, 1, 2, 3]
[0, 1, 2, 3, 4, 5]
>>>

recursively split list into sub lists based on first element length

I am breaking my head around this small issue which I am sure can (and should) be solved recursively.
# split list in sublists based on length of first element.
list = [3, 1, 2, 3, 4, 1, 2, 3, 4]
#* #*
# *number of elements of the sublist
It is better shown than explained, the above should result to:
[[1, 2, 3], [1, 2, 3, 4]]
The lists I am processing always respect this logic, the first element is always the length of the following n elements.
EDIT:
Based on some of the suggestions, I simply added a yield to get it done lazily.
def split(ls):
"""
func that given a list extracts sub lists with the length indicated by the first element
[2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4] => [[1, 2], [1, 2, 3], [1, 2, 3, 4]]
"""
res = []
while ls:
dim = ls[0]
yield ls[1:dim + 1]
ls = ls[dim + 1:]
return res
>>> list(split([2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4]))
[[1, 2], [1, 2, 3], [1, 2, 3, 4]]
Simple slicing will do:
>>> a = [3, 1, 2, 3, 4, 1, 2, 3, 4]
>>> c = []
>>> while len(a) :
... b = a[0]
... c.append( a[1:b+1] )
... a = a[b+1:]
...
>>> c
[[1, 2, 3], [1, 2, 3, 4]]
Here is a way to achieve what you want:
numbers = [3, 1, 2, 3, 4, 1, 2, 3, 4]
result = []
def split_list(list_):
first = list_.pop(0)
result.append(list_[:first])
if len(list_[first:]) > 0:
split_list(list_[first:])
split_list(numbers)
print(result)
You can use itertools.islice here.
>>> from itertools import islice
>>> lst = [3, 1, 2, 3, 4, 1, 2, 3, 4]
>>> def chunks(lst):
... t=iter(lst)
... c=next(t,None)
... while c:
... yield list(islice(t,None,c))
... c=next(t,None)
...
>>> list(chunks(lst))
[[1, 2, 3], [1, 2, 3, 4]]
I've edited my answer as inspired by someone else's in this thread. This doesn't consume the original array and uses recursion instead of looping.
numbers = [3, 1, 2, 3, 4, 1, 2, 3, 4, 3,1,1,1,1]
def do_take(numbers: []):
result = []
to_take = numbers[0]
result.append(numbers[1:to_take + 1])
if len(numbers) > to_take:
result.append(do_take(numbers[to_take + 1:]))
return result
print(do_take(numbers))
print(numbers)
Results in the following output:
# python /tmp/breakup.py
[[1, 2, 3], [[1, 2, 3, 4], [[1, 1, 1], [[]]]]]
[3, 1, 2, 3, 4, 1, 2, 3, 4, 3, 1, 1, 1, 1]

How to convert list of 68 elements into matrix of 68x68?

I have a list [1,2,3,4,5...,68] I want it to make as [[1,1,1....68 times],[2,2,2...68 times],.....[68,68,68... 68 times]].
i.e. If I consider list as a matrix then I have 68x1 matrix want to make it 68x68 by repeating elements in column, just like a repmat function in MATLAB.
I tried np.tile like this
np.tile(y_1,(1,68))
where y_1 has 68 elements but it ended up giving as [1,2,3,4....68]
I also tried
y_1*68
but it gave [1,2,3,4....68,1,2,3,4.....68,1,2...68....] which is again not I want
How can I do this ?
You could use a list comprehension.
lis = [1,2,3,4,5]
rep = [[i]*len(lis) for i in lis]
print(rep)
Output:
[[1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3], [4, 4, 4, 4, 4], [5, 5, 5, 5, 5]]
with a list comprehension.
mat = range(1, 69)
[[elt]*len(mat) for elt in mat]
You can replicate the matlab repmat function like this:
def repmat(mat):
return [[elt]*len(mat) for elt in mat]
repmat([0, 1, 2, 3])
output:
[[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]]
Alternatively, with a lambda:
repmat2 = lambda mat:[[elt]*len(mat) for elt in mat]
repmat2([0, 1, 2, 3])
Try:
np.tile(np.reshape(y_1,(68,1)),(1,68))

Repetition in Python for each element of list

I have a list a = [3,7,4]
I want to generate a list repetition of a sequence generated from each element of list like that:
b = [1,1,1,2,2,2,2,2,2,2,3,3,3,3]
Try like this.
result = []
for i,j in enumerate(a):
result += [i+1 for n in range(j)]
Result
[1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
input:
a = [3,7,4]
b = [x for x in range(len(a)+1)[1::] for j in range(a[x-1])]
result:
[1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3]

reassigning row/list in a 2d list in python

I was trying to create an 2d list in python that was x + 1,y + 1 sized and had some initial values. Those initial values are that the first row contains the numbers 0 to 'x' and the first column contains the numbers 0 to 'y' (both inclusively)
Lets say x and y were 3 and 4.
So I went:
listName = [range(0, x + 1)] * (y + 1);
This gives me a 2d list that has 5 rows and each row is a list with the numbers 0 to 3 giving 4 indexes on each row (4 columns):
[[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3]]
I understand that at this point I have a 2d array, but each row is an instance so if I changed any value in each row, all the rows would reflect that change. So to fix that I decided to set each row to a new unique list:
for row in listName:
row = range(0, x + 1);
But I noticed that this seems to have no effect, my original list Even if I went:
for row in listName:
row = ["A", "B", "C", "D"];
Printing before and after the assignment shows 'row' is getting changed, but outside the loop, I get my original list when I print it. Even though I've found another way to do what I want, I can't seem to figure out why this happens. Any ideas?
Slice-assign in order to modify the existing list, instead of just rebinding the name.
row[:] = ...
Also, you're constructing it incorrectly.
listName = [range(0, x + 1) for z in range(y + 1)]
When you assign a list to a name you're effectively instantiating a new list. Python has a special syntax that allows you to do this:
row[:] = …
>>> listName = [range(0, x + 1)] * (y + 1);
>>> listName
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> for row in listName:
... row[:] = range(0, x+1)
...
>>> listName
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> for row in listName:
... row[:] = range(0, x+6)
...
>>> listName
[[0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8]]
But based on your original question, did you want to do this?
>>> [range(0, x+1)] + [[i] + [0]*x for i in xrange(1, y+1)]
[[0, 1, 2, 3], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0], [4, 0, 0, 0]]
But I noticed that this seems to have no effect, my original list
Because row = range(0, x + 1) does not mean "The contents of the thing that row refers to shall be replaced with the contents of the list range(0, x + 1)"; it means "The name row shall cease referring to what it currently refers to, and instead refer to the list range(0, x + 1)".

Categories

Resources