I would like to declare a dynamic 2 dimensional array in python. The number of columns will be fixed while the number of rows should be dynamic. am willing to use numpy as well. I am using python 3, so xrange does not work. Appreciate your help.
Here is how I would go about doing it
array2d = [list() for f in xrange(n)]
This creates N empty lists. From here you can index them like
array2d[x][y]
An Example in use
array2d = [list() for f in xrange(3)] # We have Three Empty Rows
# Array looks like this -- [[] [] []]
#lets add an item into the first row
array2d[0].append("A")
#Now it looks like this -- [["A"] [] []]
This should solve your problem. The function grow_rows will add any needed rows, using a fixed column count and initializing the entries with 0 (which you can change to anything you like):
def grow_rows(arr, row_cnt, col_cnt):
missing = row_cnt - len(arr)
if missing > 0:
arr.extend([[0] * col_cnt for i in range(missing)])
Here's an example using a fixed column count of 3. Before accessing an element in a row that has not yet been allocated, it calls grow_rows to create the needed rows:
col_cnt = 3
arr = []
print(arr)
grow_rows(arr, 2, col_cnt)
print(arr)
arr[1][2] = 123
print(arr)
Here is the output:
[]
[[0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, 123]]
Example for Python 3:
matrix = [list() for f in range(2)]
print(matrix)
Output:
[[], []]
Related
I am trying to create a 2d array by the following two methods. Now I get the 2d array when I use the list comprehension but I receive and error of Index out of bound when I use the normal for loop. Can someone please explain me as to why did this happen?
r=3
c=4
new = []
temp =[]
for i in range(r):
for j in range(c):
new[i][j]=0
print(new)
Result - IndexError: list index out of range
temp = [[0 for _ in range(c)] for _ in range(r)]
print("Temp", temp)
Result - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
You're trying to access values from an empty list, use append with an auxiliary list as follow:
>>> for i in range(r):
... aux = []
... for j in range(c):
... aux.append(0)
... new.append(aux)
In the second approach
temp = [[0 for _ in range(c)] for _ in range(r)]
you set each element of the new temp list to another list and fill it in.
When you do this in the first approach:
new[i][j]=0
you have two problems, first new[i] is beyond the range of the zero sized list. This blows up. If it didn't give an error, you are then trying to index into a thing that doesn't exist. Even if you could make it an empty list by default, the index j would also be out of range.
I have tried many things but still stuck. This is mostly because I'm failing to understand how python loops through an array or what options I have to loop through it.
I want to build an array: 4 columns, 18 rows.
I need the first column of each row to be a persons name in the person_list. Every 3 rows of my array I would then increment to the next person.
It would seem that my loop is not looping through the array the way I intended. It seems that it sets all values in the first column equal to the person_list value.
person_list = ["person1", "person2","person3","person4","person5","person6"]
my_array = [[0]*4]*len(person_list)*3
i=0
j=1
for row in my_array:
while j <= 3:
row[0] = person_list[i]
j+=1
j=1
i+=1
So the goal would be the resulting array
[
["person1", 0, 0, 0],
["person1", 0, 0, 0],
["person1", 0, 0, 0],
["person2", 0, 0, 0],
["person2", 0, 0, 0],
["person2", 0, 0, 0],
["person3", 0, 0, 0],
["person3", 0, 0, 0],
...
]
The problem seems to stem from the way my_array was initialized. Each row is 'nested' with the other rows, by that I mean if you try to modify my_array[0], you will end up modify all the remaining rows. Here is an example to illustrate that:
my_array[0].insert(0, 'hello_world')
# this prints:
# [['hello_world', 0, 0, 0],
['hello_world', 0, 0, 0],
....
['hello_world', 0, 0, 0]]
To get around, this you can use numpy to initialize your array of zeros or do something like this:
my_array = [[0, 0, 0, 0] for i in range(18)]
To make the code slight more concise and print the expected output, you can then do the following:
for i in range(len(person_list)):
# person1 : idx 0, 1, 2
# person2 : idx 3, 4, 5
# ...
end_idx = (i + 1) * 3
start_idx = end_idx - 3
for sub_arr in arr[start_idx:end_idx]:
sub_arr.insert(0, person_list[i])
Hope this helped!
You could use the modulo % to increment at certain intervals. For example, row%3==0 will return True at multiples of 3. FYI in your above code you were not resetting the row variable every interval of 3.
person_list = ["person1", "person2","person3","person4","person5","person6"]
my_array = [[0]*4]*len(person_list)*3
j=0
i=0
for row in my_array:
if j%3==0:
row[0] = person_list[i]
i+=1
j+=1 # increment the row here
I think everything is good in your code, you are just multiplying it by 3 :
person_list = ["person1", "person2","person3","person4","person5","person6"]
my_array = [[0]*4]*len(person_list)
i=0
j=1
for row in my_array:
while j <= 3:
row[0] = person_list[i]
j+=1
j=1
i+=1
I think its this like which needs to change from my_array = [[0]*4]*len(person_list)*3 to my_array = [[0]*4]*len(person_list)
So I think NeuralX was helpful in pointing out the way I create the array is not going to work for what I intend to do to it. He is absolutely correct when I run a change it will update every entry in the final array.
In more searching with working with nested lists, I have found how I should create the array so that I can update nested lists individually by looping through it. The final results are going to be below.
person_list = ["person1", "person2","person3","person4","person5","person6"]
# The way I create the array appears the be the main root cause here. I need to create it like this
my_array = [[0 for x in range(4)] for y in range(sum(person_assessments))]
i=0
j=0
for person in person_list:
for assessment in range(1, 4):
my_array[i][0] = person
# print(person, ", ", assessment)
# print(i,", ", j,", ", person)
i+=1
j += 1
print(my_array)
All I am trying to do is populate an array with numbers in order. So, array[0][0] = 0, array[0][1]=1, etc. Why is this not working? I cannot figure it out.
def populateArray(ar):
count = 0
i=0
j=0
while (i<len(ar)):
while (j<len(ar[i])):
ar[i][j] = count
count = count + 1
j=j+1
j=0
i=i+1
return ar
numColumns = input('how many columns?')
numRows = input('how many rows?')
arr = [[0]*int(numColumns)]*int(numRows)
arr=populateArray(arr)
print(arr)
when you initiate your arr variable, you are multiplying a list of lists with a number, this results in a "mess" because what you actually do it is to multiply only the reference of the first list (from your list of lists), so actually you have in your arr only one list and a bunch of reference to that list, to fix this you can do:
arr = [[0] * int(numColumns) for _ in range(int(numRows))]
or:
arr = [[0 for _ in range(int(numColumns))] for _ in range(int(numRows))]
after changing this in your code, for numRows = 3 and numColumns = 4 you get:
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
When you use this syntax to create multi dimensional array
arr = [[0]*int(numColumns)]*int(numRows)
the reference of same element is created many times , so if you assign a value to one of them then you are basically changing all the elements because they all reference to the same data.
for ex :
arr = [[0]*int(numColumns)]*int(numRows)
arr[0][1]=2
print(arr)
output
[[0, 2], [0, 2], [0, 2], [0, 2]]
I only changed one element and this is the result .
you should use :
arr = [[0 for i in range(int(numColumns))] for j in range(int(numRows))]
arr[0][1]=2
print(arr)
output :
[[0, 2], [0, 0], [0, 0], [0, 0]]
You can do this:
numColumns = input('how many columns?')
numRows = input('how many rows?')
arr = [[i+j for i in range(int(numRows))] for j in range(int(numColumns))]
arr=populateArray(arr)
print(arr)
The problem with your code is that you append same array to the main array multiple times, like this [l, l, l] and l is a list.
So when ever you change an elemenet of l it will change all of ls in your list.
So, your code works fine but each time you change another list, all of previous list will be effected.
You can also make use of numpy for creating the structure, followed by using numpy.tolist() for converting it to a python list
import numpy as np
numColumns = int(input('how many columns?'))
numRows = int(input('how many rows?') )
arr = np.arange(numRows*numColumns).reshape(numRows, numColumns).tolist()
print(arr)
This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 6 years ago.
I wonder What is the difference between this two different method of 2D matrix initialization in python.
m =[]
K = []
for x in range(0,W+1):
m.append(0)
for x in range(0,n+1):
K.append(m)
and
l = []
for j in range(0,n+1):
l.append([])
for i in range(0,W+1):
l[j].append(0))
when I tried to print l and K the both gave the same answer but when I tried to implement it in code the output of program changed.
the earlier one(K) gave an incorrect answer but later one(l) when implemented in the program gave a correct answer.
In the first one, you are storing the same reference to list m in k. Change in m will be reflected in all the reference.
Where as in second, you are creating new lists in l. Hence, change in one is independent of another.
Alternatively, simpler way to initialize list is as:
Holding same reference to list (similar to your first approach) is as:
>>> row, columns = 2, 3
>>> my_list = [[0]*columns]*row
>>> my_list
[[0, 0, 0], [0, 0, 0]]
>>> my_list[0][1] = 1 # changing value
>>> my_list
[[0, 1, 0], [0, 1, 0]]
# ^ ^ Reflected in all
Holding different reference to the list (similar to your second approach) is as:
>>> my_list = [[0]*columns for i in range(row)]
>>> my_list
[[0, 0, 0], [0, 0, 0]]
>>> my_list[0][1] = 1 # changing value
>>> my_list
[[0, 1, 0], [0, 0, 0]]
# ^ only one value is changed
Given the following problem, what is the most efficient (or reasonably efficient) way to do this in Python:
Problem. Given a list of lists,
L = [list_0, list_1, list_2, list_3, ..., list_n]
where len(list_i) <= 3, let's say, for each list inside of L. How can we split up L into L_1, L_2, L_3, where L_1 has only length 1 lists, L_2 has only length 2 lists, and L_3 has only length 3 lists?
Potential Solutions. Here's the best I could do; I've also included a sample set here as well. It runs in around 8.6 seconds on my PC.
import time
# These 4 lines make a large sample list-of-list to test on.
asc_sample0 = [[i] for i in range(500)]
asc_sample1 = [[i,j] for i in range(500) for j in range(20)]
asc_sample2 = [[i,j,k] for i in range(20) for j in range(10) for k in range(20)]
asc_sample = asc_sample0 + asc_sample1 + asc_sample2
start = time.clock()
cells0 = [i for i in asc if len(i) == 1]
cells1 = [i for i in asc if len(i) == 2]
cells2 = [i for i in asc if len(i) == 3]
print time.clock() - start
I also attempted to "pop" elements off and append to lists cells0, etc., but this took significantly longer. I also attempted to append and then remove that element so I could get through in one loop which worked okay when there were, say, 10^10 lists of size 1, but only a few of size 2 and 3, but, in general, it was not efficient.
I'd mostly appreciate some neat ideas. I know that one of the answers will most likely be "Write this in C", but for now I'd just like to look at Python solutions for this.
An old fashioned solution might work better here:
cells0, cells1, cells2 = [], [], []
for lst in asc_sample:
n = len(lst)
if n == 1:
cells0.append(lst)
elif n == 2:
cells1.append(lst)
else:
cells2.append(lst)
This is definitely one of the best because it runs in parallel. Another thing that you should look at though is the itertools.groupby and the built-in filter method.
result = dict()
for lst in L:
result.setdefault(len(lst), []).append(lst)
print result
Output
{
1: [[0], [1], [2], [3]],
2: [[0, 0], [0, 1], [0, 2]],
3: [[0, 0, 0], [0, 0, 1], [0, 0, 2]]
}
Indexing a list/tuple should be faster than doing key lookups. This is about 30% faster than the version given in the question
cells = [],[],[],[] # first list here isn't used, but it's handy for the second version
for i in asc:
cells[len(i)].append(i)
Slightly faster again by extracting the append methods (On larger lists this is almost twice as fast as the OP)
cells = [],[],[],[]
appends = [x.append for x in cells]
for i in asc:
appends[len(i)](i)