Creating a 2D array such as
x = [range(i, i+10) for i in xrange(1,100,10)]
and indexing using the colon operator like this
>>> x[2][:]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
works as expected. It returns all of row 2.
However, if I want to retrieve all of column 2, I would instinctively do
>>> x[:][2]
But this also returns
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
What is the reasoning behind this? I would intuitively think that this returns the column 2 of each row.
(Also, I am aware I can use numpy to do x[:,2] or I could use list comprehensions to accomplish this, that's not my question)
A colon on the right side of an index means everything after the specified index. A colon on the left side of an index means everything before, but not including, the index.
In Python, a colon is required at the beginning of every block of code. It is easier to explain with an example. Notice how at the end of the if statement I have a colon. This tells Python that the next line of indented code should only be run IF the condition is true.
Two-dimensional (2D) arrays are indexed by two subscripts, one for the row and one for the column. Each element in the 2D array must by the same type, either a primitive type or object type.
This means starting from the 3th element from the end, which is number 4, and counting backwards by 2 (skipping 1) until the beginning of the array is reached.
x[2][:]
will return the 3rd row of your array, and then return all elements inside that row.
x[:][2]
will return all the rows of your array, and then return the 3rd row of them all.
Effectively, they're both the same, x[2][:] == x[:][2]
.
Printing them in the console it's obvious why this occurs:
In [138]: x[2]
Out[138]: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
In [139]: x[2][:]
Out[139]: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
In [140]: x[:]
Out[140]:
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
[31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
[51, 52, 53, 54, 55, 56, 57, 58, 59, 60],
[61, 62, 63, 64, 65, 66, 67, 68, 69, 70],
[71, 72, 73, 74, 75, 76, 77, 78, 79, 80],
[81, 82, 83, 84, 85, 86, 87, 88, 89, 90],
[91, 92, 93, 94, 95, 96, 97, 98, 99, 100]]
In [141]: x[:][2]
Out[141]: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
If you wish to get the columns then you can effectively transpose the lists using list(zip(*x))
(added the list
in for Py 3). You could then do:
In [3]: list(zip(*x))[2]
Out[3]: (3, 13, 23, 33, 43, 53, 63, 73, 83, 93)
That aside, I'd suggest you use numpy
instead for this kind of work.
The reason is that [:]
just means "everything", and that the two indexing operations in a row are completely independent.
y = x[2][:]
is
tmp = x[2]
y = tmp[:] # this only makes a copy, does nothing else
Similarly,
y = x[:][2]
is
tmp = x[:] # this only makes a copy, does nothing else
y = tmp[2]
in effect both just mean
y = x[2]
There is no 2D indexing going on at any point, Python doesn't have 2D indexing (although numpy has hacks that make it work like there is actual 2D indexing going on).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With