Python: list of lists

Question:

Running the code

listoflists = []
list = []
for i in range(0,10):
    list.append(i)
    if len(list)>3:
        list.remove(list[0])
        listoflists.append((list, list[0]))
print listoflists

returns

[([7, 8, 9], 0), ([7, 8, 9], 0), ([7, 8, 9], 0), ([7, 8, 9], 1), ([7, 8, 9], 2), ([7, 8, 9], 3), ([7, 8, 9], 4), ([7, 8, 9], 5), ([7, 8, 9], 6), ([7, 8, 9], 7)]

so somehow the first argument of each tuple (list) is being updated each time in the list of lists, but the second argument list[0] is not. Can someone explain what’s going on here and suggest a way to fix this? I’d like to output

[([0],0), ([0,1],0), ...
Asked By: Carl

||

Answers:

First, I strongly recommend that you rename your variable list to something else. list is the name of the built-in list constructor, and you’re hiding its normal function. I will rename list to a in the following.

Python names are references that are bound to objects. That means that unless you create more than one list, whenever you use a it’s referring to the same actual list object as last time. So when you call

listoflists.append((a, a[0]))

you can later change a and it changes what the first element of that tuple points to. This does not happen with a[0] because the object (which is an integer) pointed to by a[0] doesn’t change (although a[0] points to different objects over the run of your code).

You can create a copy of the whole list a using the list constructor:

listoflists.append((list(a), a[0]))

Or, you can use the slice notation to make a copy:

listoflists.append((a[:], a[0]))
Answered By: Greg Hewgill

Lists are a mutable type – in order to create a copy (rather than just passing the same list around), you need to do so explicitly:

listoflists.append((list[:], list[0]))

However, list is already the name of a Python built-in – it’d be better not to use that name for your variable. Here’s a version that doesn’t use list as a variable name, and makes a copy:

listoflists = []
a_list = []
for i in range(0,10):
    a_list.append(i)
    if len(a_list)>3:
        a_list.remove(a_list[0])
        listoflists.append((list(a_list), a_list[0]))
print listoflists

Note that I demonstrated two different ways to make a copy of a list above: [:] and list().

The first, [:], is creating a slice (normally often used for getting just part of a list), which happens to contain the entire list, and thus is effectively a copy of the list.

The second, list(), is using the actual list type constructor to create a new list which has contents equal to the first list. (I didn’t use it in the first example because you were overwriting that name in your code – which is a good example of why you don’t want to do that!)

Answered By: Amber

When you run the code

listoflists.append((list, list[0]))

You are not (as I think you expect) adding a copy of list to the end of listoflists. What you are doing is adding a reference to list to the end of listoflists. Thus, every time you update list, it updates every reference to list, which in this case, is every item in listoflists

What you could do instead is something like this:

listoflists = []
for i in range(1, 10):
    listoflists.append((range(i), 0))
Answered By: Strigoides

You’re also not going to get the output you’re hoping for as long as you append to listoflists only inside the if-clause.

Try something like this instead:

import copy

listoflists = []
list = []
for i in range(0,10):
    list.append(i)
    if len(list)>3:
        list.remove(list[0])
    listoflists.append((copy.copy(list), copy.copy(list[0])))
print(listoflists)
Answered By: Michael

The list variable (which I would recommend to rename to something more sensible) is a reference to a list object, which can be changed.

On the line

listoflists.append((list, list[0]))

You actually are only adding a reference to the object reference by the list variable. You’ve got multiple possibilities to create a copy of the list, so listoflists contains the values as you seem to expect:

Use the copy library

import copy
listoflists.append((copy.copy(list), list[0]))

use the slice notation

listoflists.append((list[:], list[0]))
Answered By: kajk

I came here because I’m new with python and lazy so I was searching an example to create a list of 2 lists, after a while a realized the topic here could be wrong…
This is a code to create a list of lists:

listoflists = []
for i in range(0,2):
    sublist = []
    for j in range(0,10)
        sublist.append((i,j))
    listoflists.append(sublist)
print listoflists

this is the output:

[
    [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9)],
    [(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9)]
]

The problem with your code seems to be you are creating a tuple with your list and you get the reference to the list instead of a copy. That I guess should fall under a tuple topic…

Answered By: user110954

Time traveller here

List_of_list =[([z for z in range(x-2,x+1) if z >= 0],y) for y in range(10) for x in range(10)]

This should do the trick. And the output is this:

[([0], 0), ([0, 1], 0), ([0, 1, 2], 0), ([1, 2, 3], 0), ([2, 3, 4], 0),  ([3, 4, 5], 0), ([4, 5, 6], 0), ([5, 6, 7], 0), ([6, 7, 8], 0), ([7, 8, 9], 0), ([0], 1), ([0, 1], 1), ([0, 1, 2], 1), ([1, 2, 3], 1), ([2, 3, 4], 1), ([3, 4, 5], 1), ([4, 5, 6], 1), ([5, 6, 7], 1), ([6, 7, 8], 1), ([7, 8, 9], 1), ([0], 2), ([0, 1], 2), ([0, 1, 2], 2), ([1, 2, 3], 2), ([2, 3, 4], 2), ([3, 4, 5], 2), ([4, 5, 6], 2), ([5, 6, 7], 2), ([6, 7, 8], 2), ([7, 8, 9], 2), ([0], 3), ([0, 1], 3), ([0, 1, 2], 3), ([1, 2, 3], 3), ([2, 3, 4], 3), ([3, 4, 5], 3), ([4, 5, 6], 3), ([5, 6, 7], 3), ([6, 7, 8], 3), ([7, 8, 9], 3), ([0], 4), ([0, 1], 4), ([0, 1, 2], 4), ([1, 2, 3], 4), ([2, 3, 4], 4), ([3, 4, 5], 4), ([4, 5, 6], 4), ([5, 6, 7], 4), ([6, 7, 8], 4), ([7, 8, 9], 4), ([0], 5), ([0, 1], 5), ([0, 1, 2], 5), ([1, 2, 3], 5), ([2, 3, 4], 5), ([3, 4, 5], 5), ([4, 5, 6], 5), ([5, 6, 7], 5), ([6, 7, 8], 5), ([7, 8, 9], 5), ([0], 6), ([0, 1], 6), ([0, 1, 2], 6), ([1, 2, 3], 6), ([2, 3, 4], 6), ([3, 4, 5], 6), ([4, 5, 6], 6), ([5, 6, 7], 6), ([6, 7, 8], 6), ([7, 8, 9], 6), ([0], 7), ([0, 1], 7), ([0, 1, 2], 7), ([1, 2, 3], 7), ([2, 3, 4], 7), ([3, 4, 5], 7), ([4, 5, 6], 7), ([5, 6, 7], 7), ([6, 7, 8], 7), ([7, 8, 9], 7), ([0], 8), ([0, 1], 8), ([0, 1, 2], 8), ([1, 2, 3], 8), ([2, 3, 4], 8), ([3, 4, 5], 8), ([4, 5, 6], 8), ([5, 6, 7], 8), ([6, 7, 8], 8), ([7, 8, 9], 8), ([0], 9), ([0, 1], 9), ([0, 1, 2], 9), ([1, 2, 3], 9), ([2, 3, 4], 9), ([3, 4, 5], 9), ([4, 5, 6], 9), ([5, 6, 7], 9), ([6, 7, 8], 9), ([7, 8, 9], 9)]    

This is done by list comprehension(which makes looping elements in a list via one line code possible). The logic behind this one-line code is the following:

(1) for x in range(10) and for y in range(10) are employed for two independent loops inside a list

(2) (a list, y) is the general term of the loop, which is why it is placed before two for’s in (1)

(3) the length of the list in (2) cannot exceed 3, and the list depends on x, so

[z for z in range(x-2,x+1)] 

is used

(4) because z starts from zero but range(x-2,x+1) starts from -2 which isn’t what we want, so a conditional statement if z >= 0 is placed at the end of the list in (2)

[z for z in range(x-2,x+1) if z >= 0] 
Answered By: mathguy
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.