Python slicing of list of list - python

Say I have a list of lists
>>> s = [ [1,2], [3,4], [5,6] ]
I can access the items of the second list:
>>> s[1][0]
3
>>> s[1][1]
4
And the whole second list as:
>>> s[1][:]
[3, 4]
But why does the following give me the second list as well?
>>> s[:][1]
[3, 4]
I thought it would give me the second item from each of the three lists.
One can use list comprehension to achieve this (as in question 13380993), but I'm curious how to properly understand s[:][1].

s[:] returns a copy of a list. The next [...] applies to whatever the previous expression returned, and [1] is still the second element of that list.
If you wanted to have every second item, use a list comprehension:
[n[1] for n in s]
Demo:
>>> s = [ [1,2], [3,4], [5,6] ]
>>> [n[1] for n in s]
[2, 4, 6]

The behavior can be understood easily, if we decompose the command:
s[:]
will return the entire list:
[[1, 2], [3, 4], [5, 6]]
selecting [1] now gives the second list (python indexing starts at zero).

s[:][1] means take a shallow copy of s and give me the first element from that... While s[1][:] means give me a shallow copy of s[1]...
You may be confusing somethings that you've seen that utilise numpy which allows extended slicing, eg:
>>> a = np.array([ [1,2], [3,4], [5,6] ])
>>> a[:,1]
array([2, 4, 6])
Which with normal lists, as you say, can be done with a list-comp:
second_elements = [el[1] for el in s]

s[:] makes a copy of s, so the following [1] accesses the second element of that copy. Which is the same as s[1].
>>> s = [ [1,2], [3,4], [5,6] ]
>>> s[1]
[3, 4]
>>> s[:][1]
[3, 4]

s[1][:] means a shallow copy of the second item in s, which is [3,4].
s[:][1] means the second item in a shallow copy of s, which is also [3,4].
Below is a demonstration:
>>> s = [ [1,2], [3,4], [5,6] ]
>>> # Shallow copy of `s`
>>> s[:]
[[1, 2], [3, 4], [5, 6]]
>>> # Second item in that copy
>>> s[:][1]
[3, 4]
>>> # Second item in `s`
>>> s[1]
[3, 4]
>>> # Shallow copy of that item
>>> s[1][:]
[3, 4]
>>>
Also, [1] returns the second item, not the first, because Python indexes start at 0.

Related

How to use list slicing to append to end of list in python?

Following can be used to add a slice to append to front of list.
>>> a = [5,6]
>>> a[0:0] = [1,2,3]
>>> a
[1,2,3,5,6]
what slice to use to append to the end of list.
If you really want to use slice, you can use the length of a:
a = [5, 6]
a[len(a):] = [1, 2, 3]
a
output:
[5, 6, 1, 2, 3]
But the simplest is to directly extend a:
a = [5, 6]
a += [1, 2, 3] # or a.extend([1, 2, 3])
I think you should consider extend():
>>> a = [1, 2, 3]
>>> a.extend([4, 5, 6])
>>> a
[1, 2, 3, 4, 5, 6]
Both + and += operators are defined for list, which are semantically
similar to extend.
list + list2 creates a third list in memory, so you can return the
result of it, but it requires that the second iterable be a list.
list += list2 modifies the list in-place (it is the in-place operator,
and lists are mutable objects, as we've seen) so it does not create a
new list. It also works like extend, in that the second iterable can
be any kind of iterable.
Time Complexity
Append has constant time complexity, O(1).
Extend has time complexity, O(k).
Iterating through the multiple calls to append adds to the complexity,
making it equivalent to that of extend, and since extend's iteration
is implemented in C, it will always be faster if you intend to append
successive items from an iterable onto a list.
↳ More Information
>>> a = [1, 2, 3]
>>> a[len(a):] = [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
or
>>> a = [1, 2, 3]
>>> a += [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
You have got short answer from Jeevaa and Reblochon Masque but if you want to use for loop then try this:
a = [5,6]
b = [1,2,3]
for val in b[::-1]:#Reverse b and insert it to a
a.insert(0,val)
print(a)
Output
[1,2,3,5,6]

Mutability of lists in python

Example one: Changing the value that has been appended to b changes the value in the original list l
>>> l = [1 , 2, 3]
>>> b = []
>>> b.append(l)
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4]]
>>> l
[1, 2, 3, 4]
Example 2: l1 is appended to ans and then the value of l1 is modified. However, the value in ans remains the same.
>>> l1 = [1, 2, 3]
>>> ans = []
>>> ans.append(l1)
>>> ans
[[1, 2, 3]]
>>> l1 = [2, 3, 4]
>>> ans
[[1, 2, 3]]
I seem to be missing some fundamental point about the mutability of lists. Could someone please point it out?
You are not mutating l1. You are assigning a new object to the same name, which makes that name point to a new object. You are moving a label, not modifying an object. The only remaining reference to the list that l1 used to point to is now ans[0].
In your first example, l is a pointer, as well as b.
l is then appended to b, so b[0] now refers to the pointer.
Next, you append 4 to b[0], which is the same thing as l, so 4 is added to both b[0] and l.
In your second example, ans contains the pointer of l1, just like b contained the pointer of l
Then, you changed l1 itself by assigning it to a different array, so l1 changed but ans[0] did not.
The biggest takeaway from this is that append just changes the list, and the pointer remains the same. But when you set a variable to a different list, the pointer changes.
Replace
>>> l1 = [2, 3, 4]
with
>>> l1[:] = [2, 3, 4]
That will not assign a new list to l1.

Why does appending a list by itself create an infinite list

l = [1, 2]
l.append(l)
>>>l
[1, 2, [...]] #l is an infinite list
Why does this create an infinite list instead of creating:
l = [1, 2]
l.append(l)
>>>l
[1, 2, [1, 2]]
When you do:
l.append(l)
a reference to list l is appended to list l:
>>> l = [1, 2]
>>> l.append(l)
>>> l is l[2]
True
>>>
In other words, you put the list inside itself. This creates an infinite reference cycle which is represented by [...].
To do what you want, you need to append a copy of list l:
>>> l = [1, 2]
>>> l.append(l[:]) # Could also do 'l.append(list(l))' or 'l.append(l.copy())'
>>> l
[1, 2, [1, 2]]
>>> l is l[2]
False
>>>
Easy, because each object will have a reference to itself in the third element. To achieve [1, 2, [1, 2]] then use a copy of the list.
l.append(l[:])

count number of elements with a list that also contains a list

>>> a = [1, 2, [3, 4], 5]
>>> print(len(a))
4
The length of the list is 4, why is the element count 4 and not 5?
The element count in the outer list is 4. a[2] is one object. It doesn't matter here that that one object is also a list.
If you need to count the number of elements recursively, then do so yourself:
def recursive_element_count(ob):
if isinstance(ob, list):
return sum(recursive_element_count(elem) for elem in ob)
# anything that isn't a list counts as one element
return 1
Demo:
>>> def recursive_element_count(ob):
... if isinstance(ob, list):
... return sum(recursive_element_count(elem) for elem in ob)
... return 1
...
>>> a = [1, 2, [3, 4], 5]
>>> recursive_element_count(a)
5
Do you know sets from mathematic? That's similar in Python, in lists-tuples-sets etc. if there is a list in list or tuple in tuple etc. they are one element.
a=[1,2,3]
b=[2,3]
a.append(b)
print (a)
print (len(a))
Output:
>>>
[1, 2, 3, [2, 3]]
4
>>>
Thats because len(a)=4. [2,3] is an element of list(a).
As the inner list assumed as one object the len returned 4 . you can use the following code for calculate the length of all elements :
>>> a = [1, 2, [3, 4], 5]
>>> sum(len(i) if isinstance(i,list) else 1 for i in a)
5
isinstance() function used for check the type of object .

integer extraction from list of lists in python

I have a list that contain lists:
mylist=[[2],[9],[3],[5],[7]]
Is there a way in python to get the value of the inner list (not just print it)?
Therefore, we would get integer 2 from the list mylist[0]. Without iterating the whole mylist.
If you want to get a specific value, use mylist[instance][0].
This would work, because it gets the ith value, but then gets the 0th value of that because it is still a list:
>>> mylist=[[2],[9],[3],[5],[7]]
>>> mylist[0]
[2]
>>> mylist[0][0]
2
>>>
Alternatively, you could flatten it and then access it normally:
>>> mylist=[[2],[9],[3],[5],[7]]
>>> mylist = [item for sub in mylist for item in sub]
>>> mylist
[2, 9, 3, 5, 7]
>>> mylist[0]
2
>>>
A list of lists is similar to having a 2-D array. To reference an element of the inner list, just use
mylist[i][j]
where i refers to the index of the list and j to the element in that list.
In the case of 2, this would be:
mylist[0][0]
Think of your list like this:
mylist=
[[2],
[9],
[3],
[5],
[7]]
mylist[0] = [2] which is an array, to access the number in the array mylist as explained is mylist[0][0] which = the int 2
eg
mylist[1][0] = 2
If mylist was
mylist=
[[2, 3],
[9, 10],
[3, 4],
[5, 6],
[7, 8]]
mylist[0][1] = 3 and mylist[1][1] = 10
mylist=[[2],[9],[3],[5],[7]]
newList=[]
for each in str(mylist).replace('[','').replace(']','').strip().split(','):
newList.append(int(each))
print newList
or
newList = eval('[' + str(mylist).replace('[','').replace(']','').strip() +']')

Categories

Resources