Is there a way in Python to initialize a multi-dimensional array / list without using a loop?
Sure there is a way
arr = eval(`[[0]*5]*10`)
or
arr = eval(("[[0]*5]+"*10)[:-1])
but it's horrible and wasteful, so everyone uses loops (usually list comprehensions) or numpy
Depending on your real needs, the de facto "standard" package Numpy might provide you with exactly what you need.
You can for instance create a multi-dimensional array with
numpy.empty((10, 4, 100)) # 3D array
(initialized with arbitrary values) or create the same arrays with zeros everywhere with
numpy.zeros((10, 4, 100))
Numpy is very fast, for array operations.
The following does not use any special library, nor eval:
arr = [[0]*5 for x in range(6)]
and it doesn't create duplicated references:
>>> arr[1][1] = 2
>>> arr
[[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
Sure, you can just do
mylist = [
[1,2,3],
[4,5,6],
[7,8,9]
]
I don't believe it's possible.
You can do something like this:
>>> a = [[0] * 5] * 5
to create a 5x5 matrix, but it is repeated objects (which you don't want). For example:
>>> a[1][2] = 1
[[0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]]
You almost certainly need to use some kind of loop as in:
[[0 for y in range(5)] for x in range(5)]
Recursion is your friend :D
It's a pretty naive implementation but it works!
dim = [2, 2, 2]
def get_array(level, dimension):
if( level != len(dimension) ):
return [get_array(level+1, dimension) for i in range(dimension[level])]
else:
return 0
print get_array(0, dim)
It depends on what you what to initialize the array to, but sure. You can use a list comprehension to create a 5×3 array, for instance:
>>> [[0 for x in range(3)] for y in range(5)]
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> [[3*y+x for x in range(3)] for y in range(5)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14]]
Yes, I suppose this still has loops—but it's all done in one line, which I presume is the intended meaning of your question?
a = [[]]
a.append([1,2])
a.append([2,3])
Then
>>> a
[[1, 2], [2, 3]]
If you're doing numerical work using Numpy, something like
x = numpy.zeros ((m,n))
x = numpy.ones ((m,n))
Python does not have arrays. It has other sequence types ranging from lists to dictionaries without forgetting sets - the right one depends on your specific needs.
Assuming your "array" is actually a list, and "initialize" means allocate a list of lists of NxM elements, you can (pseudocode):
for N times: for M times: add an element
for N times: add a row of M elements
write the whole thing out
You say you don't want to loop and that rules out the first two points, but why?
You also say you don't want to write the thing down (in response to JacobM), so how would you exactly do that? I don't know of any other way of getting a data structure without either generating it in smaller pieces (looping) or explicitly writing it down - in any programming language.
Also keep in mind that a initialized but empty list is no better than no list, unless you put data into it. And you don't need to initialize it before putting data...
If this isn't a theoretical exercise, you're probably asking the wrong question. I suggest that you explain what do you need to do with that array.
You can do by this way:
First without using any loop:
[[0] * n] * m
Secondly using simple inline list comprehension:
[[0 for column in range(n)] for row in range(m)]
You can use N-dimensional array (ndarray). Here is the link to the documentation. http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
Related
time_count = [[0, 0, 0, 0]] * 4
j = 0
for i in range(len(time_count)):
time_count[i][1] = j
j += 1
print(time_count)
Output:
[[0, 3, 0, 0], [0, 3, 0, 0], [0, 3, 0, 0], [0, 3, 0, 0]]
I would expect the output to be like:
[[0,0,0,0],[0,1,0,0],[0,2,0,0],[0,3,0,0]]
can someone explain why every index[1] is 3 ?
Easy fix:
time_count = [[0, 0, 0, 0] for _ in range(4)]
As Klaus D. has alluded, using the * operator on nested lists is usually a bad idea, as it duplicates the contents by copying the references. You won't notice this when multiplying sequences of immutable types, e.g. a list of integers, but when the elements are mutable, you get duplicates.
It's not good to write a list as [[0, 0, 0, 0]]*4. Lists are mutable. Each time you change any of the list elements all the copies of it will change. one good way to write is as below because that way you are not copying list elements.
[[0, 0, 0, 0] for i in range(4)]
The * operator just creates a new reference to the original list (here [0, 0, 0, 0]).
If you change the original list as time_count[i][1] = j, all the references reflect the same changes.
If you want to create a new list, you can use the extend method with a loop on it :
time_count = []
time_count.extend([0,0,0,0] for _ in range(4))
Now, all the element list in time_count store separate memory and can have different values.
Do:
time_count = [[0, 0, 0, 0]] * 4
print([[v if x!=1 else i for x,v in enumerate(a)] for i,a in enumerate(time_count)])
Output:
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 2, 0, 0], [0, 3, 0, 0]]
UPDATE:
Explanation:
Use enumerate to iterate trough both the indexes and values of the list time_count.
Use enumerate again to iterate trough both the indexes and values of the list a. which is the iterator for time_count.
Go trough the indexes of a and say i (the index iterator for time_count) if x (the index iterator for a) is 1, otherwise say v (the iterator for a)
Note: This is all in a list comprehension
Basically, The entities of a list are pointers to a particular memory location. When one assigns list(a) to list(b) It implies that list(b) points to the same memory location as the list(a).
a = [1, 2, 3]
b = a
a = [3, 4, 5]
print(a, b)
[3, 4, 5] [1, 2, 3]
In the above-asked question if the inside of the nested list is multiplied by 4 times then all the sublists point to the same memory location. so, If one of the sublists is changed then the change is propagated to all of the sublists, Which basically creates unexpected results upon code execution. For anyone interested to know more,
the video sums up all the basic features of lists that are not obvious. It also explains the above question in further detail.
https://www.youtube.com/watch?v=_AEJHKGk9ns
This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
I hope to set up a matrix/list through for loop but I observed different results between 1D list and 2D list of the same method. I know this is a stupid way to create a list through for loop but could anyone give me a hint what caused the difference please?
m = [[0] * 4] * 4
print m
m[0] = range(4)
for i in range(4):
m[i][0] = i
print m
And the result is:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 2, 3], [3, 0, 0, 0], [3, 0, 0, 0], [3, 0, 0, 0]]
I was expecting to be [[0, 1, 2, 3], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0]].
However it worked find in 1D list as below
tmp = [0,0,0,0]
for i in range(4):
tmp[i] = i
print tmp
It printed [0,1,2,3] as I expected.
Change the first line to get:
#m = [[0] * 4] * 4
m = [([0] * 4) for _ in range(4)]
print m
m[0] = range(4)
for i in range(4):
m[i][0] = i
print m
What happened before was that you were creating four copies of the same list. Each copy looks to the same memory spaces. Python does this to conserve memory. So each time you write to one of the lists, you are in fact writing to all of them, and because the last value you write is 3, that's the value you get in all of the lists.
When you are doing m = [[0] * 4] * 4, you are creating a 2D matrix of all zeros. In other words, a list of four [0, 0, 0, 0] lists. Now, with m[0] = range(4), you are setting the first inner list to be [0,1,2,3]. Now when you do,
for i in range(4):
m[i][0] = i
you are expecting for each inner lists first element to be changed. This is one of python's quicks creep in. Object reference. When you initially create the 2D list, you are essentially referencing one list from each of the four indices. Then you replace m[0] to a separate list here: m[0] = range(4). However, all there indices refer to the same list object [0, 0, 0, 0]. And when the loop eventually finishes, value of i is 3 and that is assigned to the first element of the list. And since in index 1, 2 and 3 of m was referencing that list, all three show up as same - [3, 0, 0, 0]. Hope this helps.
I have an array which looks something like this (will have more than 5 terms but i have only used 5 terms as an example):
states = numpy.array([ [0, 0, 0],
[0, 0, 1],
[0, 2, 0],
[0, 1, 0],
[0, 1, 1]]
I cant seem to find a way to take only the 1st n terms of this array.
For example if n = 3 then:
states = numpy.array([ [0, 0, 0],
[0, 0, 1],
[0, 2, 0],]
I have tried using a loop and list.append but i keep getting the error
"list indices must be integers, not tuple"
since it returns an array which looks like this:
[[array([0, 0, 0])], [array([0, 0, 1])], [array([0, 2, 0])]
There must be a simple way to do this but i have looked for hours and cant find one!
Thank you for your help!!
Your attempt is close, but it isn't working because you are mixing Python's builtin lists with NumPy's arrays. It is important to make this distinction, because they are actually quite different.
Your solution could probably be fixed by using np.vstack instead of list.append, which would return a NumPy array rather than a list.
However, a simpler and preferred method is to use NumPy's slicing:
states[:n]
What is the easiest way to construct a zeros matrix with a cardinality of 1000 (row) x 10 (column) in Python without using numpy? (just the standard library)
Also, say if I get a list of values with 10 elements. say a=[1 2 3 ... 10], and I would like overwrite the 1st row of the zeros matrix with this list a. How would I go about doing it.
Many thanks.
PS: the reason that I would like to use the normal python list rather than numpy to construct the matrix is because of the requirement of this assignment, which does not allow any external libraries other than the python standard lib.
You can do:
m = [[0 for _ in range(10)] for _ in range(1000)]
m[0] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Note that if you use:
>>> matrix = 3*[3*[0]]
>>> matrix
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
after changing one element:
>>> matrix[0][0] = 1
>>> matrix
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
the whole column will change. So you should use this method only if you don't need your elements to be able to change independently.
I am seeing a very unusual behavior in python.. Kindly let me know what am i doing wrong!!
bc = [[0]*(n+1)]*(n+1)
for i in range(n+1):
bc[i][i] = 1
print (bc)
Output
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
I am trying to initialize the diagonal elements of two dimensional array to 1, but it is initializing all the elements with 1. I think I am doing something wrong with accessing two dimensional Array..
Also, kindly let me know how can I use two loops to access all the elements of two dimensional array.. my next step..
Thanks.
Your array is initialized incorrectly. The correct way to initialize a 2d array is this:
bc = [[0 for i in xrange(n + 1)] for i in xrange(n + 1)]
It's a common mistake, but the * operator copies the pointer to an list rather than copying the list, so while it looks like you have a 2d list, you actually have a 1d list of pointers to the same list.
the problem is that each array in your array is the same array in memory. you need a new array each time. the [[0]]*6 will for example make 6 of the same arrays in an array, editing one of them will update the other ones.
e.g.
>>> x=[1]
>>> y=x
>>> x.append(3)
>>> x
[1, 3]
>>> y
[1, 3]
>>> z=[x]*3
>>> x.append(6)
>>> z
[[1, 3, 4, 6], [1, 3, 4, 6], [1, 3, 4, 6]]
here is a fix by simply editing bc to be n+1 different arrays:
n=4
bc = [[0]*(n+1) for i in range(n+1)]
for i in range(n+1):
bc[i][i] = 1
print (bc)
[[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]
Try this one:
bc = [[0 for i in range(n+1)] for j in range(n+1)]
In your example you have only one (!) instance of [0] which is referenced multiple times. So if you change that instance, all references are changed.