0

If I have a 2D list in python Data and I want to create a slice of that 2D list, where I select all the elements from the first index and a single on from the second.

eg.

Data = [[a,b,c],[d,e,f],[h,i,g]]

and I want the list;

raw_data = [b,e,i]

Why does doing something like;

raw_data = Data[:][1]

not give the desired output? I have specified the whole first index and the 1 index for the second. Instead I get the output that is;

raw_data = [d,e,f]

Which is what I would expect to get from;

raw_data = Data[1][:]

raw_data = [d,e,f]

So;

Data[1][:] = Data[:][1]

Which is not compatible with my mental model of how lists work in python.

Instead I have to use a loop to do it;

raw_data = []

for i in xrange(0,len(Data),1):
       raw_data.append(Data[i][1])

So my question is, can anyone explain why Data[1][:] = Data[:][1] ?

Thanks for reading!

  • taking a full slice of the list makes a copy, so you are making an identical copy of the list then getting item `1` from it, or getting item `1` then making a copy of the result. – Tadhg McDonald-Jensen Aug 04 '16 at 14:15
  • I assume you are coming from a programming language that has multidimentional lists that let you do this, if so try out `numpy` as it lets you do `Data[:, 1]` to get your desired result. – Tadhg McDonald-Jensen Aug 04 '16 at 14:16
  • 'list[:]' is just a copy of whatever `list` is. Meaning that `data[:] == data` (ish) and `data[1] == data[1][:]`. So of course `data[1][:] == data[:][1]` – R Nar Aug 04 '16 at 14:17
  • 1
    `list[:]` doesn't return a slice (object), it returns a (copy of the) list. So `list[:]` == `list` and `list[:][1]` == `list[1]` == `list[1][:]`. – Aran-Fey Aug 04 '16 at 14:17

3 Answers3

2

lst[:] has no explicit start an no explicit end, so according to the Python documentation, it will return a copy of the list starting at the start and ending at the end of the list. In other words, it will return a copy of same list you have before. So:

>>> Data = [['a','b','c'],['d','e','f'],['h','i','g']]
>>> Data[:]
[['a', 'b', 'c'], ['d', 'e', 'f'], ['h', 'i', 'g']]

So when you say Data[:], that will evaluate to the same as a copy of Data, meaning that Data[:][1] essentially is just Data[1], which is [d,e,f]

If you do it the other way:

>>> Data[1]
['d', 'e', 'f']
>>> Data[1][:]
['d', 'e', 'f']

You get the second element in data, [d,e,f], then you use that same list slicing syntax as before to get that same list again.

To get what you want, I'd use a list comprehension:

>>> [x[1] for x in Data]
['b', 'e', 'i']

Simple as that.

James
  • 2,843
  • 1
  • 14
  • 24
1

Vanilla Python doesn't have two dimensional arrays, but it does allow for extensions to implement them. You have a list of lists, which is somewhat different.

The solution to your problem is to use numpy which does have a 2d array type. You can then say data[:,1]

Why your example doesn't work as you expect: data[:] means "a copy of data" and so data[:][1] means the index 1 element of the copy of data, which is [d,e,f]

James K
  • 3,692
  • 1
  • 28
  • 36
  • A two dimensional numpy array is really just an array of arrays, there's not much difference at all. For his use case numpy really doesn't add anything. – James Aug 04 '16 at 14:22
  • @James lists and numpy arrays are implemented dramatically differently, accessing columns of an array is significantly easier `Data[:,1]` then multidimensional lists. – Tadhg McDonald-Jensen Aug 04 '16 at 14:24
  • @James I tend to disagree, a numpy array is a multidimensional structure. Conceptually it is different from a list of lists. If you actually have a 2d array, and it contains data of a consistent type, then `data[:,1]` is shorter, easier to read and quicker than a comprehension. If you actually have a list of lists (eg variable length rows, inconsistent types) then the comprehension is more natural. – James K Aug 04 '16 at 14:28
0

It's pretty obvious if you go through what's happening from left to right.

raw_data = Data[:]

will give you the entirety of Data, so the whole list of lists: [[a,b,c],[d,e,f],[h,i,g]]

raw_data = Data[:][1]

will then give you the element at index 1 in this list, which is [d,e,f].

On the other hand, raw_data = Data[1] will return the element at position 1 in data, which is also [d,e,f].

[:] on this object will again return itself in its entirety.

What you are trying to do is best done with a list comprehension, such as:

raw_data = [x[1] for x in Data]

This will give you list of all second elements in all lists in Data.

Max Uppenkamp
  • 974
  • 4
  • 16