Python Forum

Full Version: How to generate the list I want?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi :)

I want to generate a list of lists of the form:

[ [0, 4, 4, 4, 4]
  [4, 0, 4, 4, 4]
  [4, 4, 0, 4, 4]
  [4, 4, 4, 0, 4]
  [4, 4, 4, 4, 0] ]
Nothing I'm trying works, it seems python wants to simplify my life by changing all the lists indices instead of just the one i'm pointing at him. Examples:

Xs = [[4]*5]*5
for i, X in enumerate(Xs):
    Xs[i][i] = 0
print Xs

Xs, t = [], [4, 4, 4, 4, 4]
for i in range(5):
    Xs.append(t)
    Xs[i][i] = 0
print Xs

Xs, t = [], [4, 4, 4, 4, 4]
for i in range(5):
    temp = t
    temp[i] = 0
    Xs.append(temp)
print Xs
print t, "f you, i don't even touch t"
outputs:
Output:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] [0, 0, 0, 0, 0] f you, i don't even touch t
In reality, I need to make a slightly bigger list, and I could totally make it by hand, but seriously what is this behaviour? Not only it's totally unintuitive, but especially the last example is ridiculous, I just can't find how to generate that... Is my logic flawed there and I'm too blind to see?

Yes I'm a bit angry because I just lost one hour to understand why my monte-carlo optimization of non-convex stuff did send me errors it shouldn't. It's easy, I don't have the starting list of indices I should have.
How about this:
from copy import deepcopy

seed = [0, 4, 4, 4, 4]
final_list = []
for i in range (len(seed)-1):
    final_list.append(deepcopy(seed))
    hold = seed[i]
    seed[i] = seed[i+1]
    seed[i+1] = hold
final_list.append(deepcopy(seed))
print(final_list)
Yeah it works.
But I made it by hand in the end, the list I needed was just twice as big.
But seriously, we need a module for that? I really have to read a whole manual just to make a simple list... Also the logic is a bit hard to follow, or to be more precise, it really seems there should be a much simpler way to go.

And especially my last example, what is going on, why does t get changed when I don't affect anything new to it?

Thank you.
Actually, I thought my solution was quite simple, a swap and append.
will work with any size seed.
You could add code to build the initial seed, and also could simplify more by using a list comprehension
Compared to the first thing I tried above, which was just "generate full list, fill the right tiles with the right number in one go", it feels, to me, overly complicated. I have to admit that whatever I feel, your code is the simplest that works haha.
I know my solution doesn't work, but I don't understand why, it really feels like a bug forcing us to go for more complicated code.
In [1]: def list_gen(fill=4, size=5):
   ...:     pattern = [fill for _ in range(size-1)]
   ...:     my_list = [pattern[:] for _ in range(size)]
   ...:     _ = [l.insert(index, 0) for index, l in enumerate(my_list)]
   ...:     return my_list
   ...:

In [2]: print(list_get())
[[0, 4, 4, 4, 4], [4, 0, 4, 4, 4], [4, 4, 0, 4, 4], [4, 4, 4, 0, 4], [4, 4, 4, 4, 0]]

In [3]: from pprint import pprint

In [4]: pprint(list_gen())
[[0, 4, 4, 4, 4],
 [4, 0, 4, 4, 4],
 [4, 4, 0, 4, 4],
 [4, 4, 4, 0, 4],
 [4, 4, 4, 4, 0]]

In [5]: pprint(list_gen(3, 10))
[[0, 3, 3, 3, 3, 3, 3, 3, 3, 3],
 [3, 0, 3, 3, 3, 3, 3, 3, 3, 3],
 [3, 3, 0, 3, 3, 3, 3, 3, 3, 3],
 [3, 3, 3, 0, 3, 3, 3, 3, 3, 3],
 [3, 3, 3, 3, 0, 3, 3, 3, 3, 3],
 [3, 3, 3, 3, 3, 0, 3, 3, 3, 3],
 [3, 3, 3, 3, 3, 3, 0, 3, 3, 3],
 [3, 3, 3, 3, 3, 3, 3, 0, 3, 3],
 [3, 3, 3, 3, 3, 3, 3, 3, 0, 3],
 [3, 3, 3, 3, 3, 3, 3, 3, 3, 0]]
a = [4, 4, 4, 4]
c = []
for i in range(4):
    b = [elem for elem in a]
    b[i] = 0
    c.append(b)
print c
Output:
[[0, 4, 4, 4], [4, 0, 4, 4], [4, 4, 0, 4], [4, 4, 4, 0]]
Pheeew I managed to find a way without a module.
Apparently, the list stays in memory as an element and the variables refering to the list are just pointers to it, and not a container containing a separate value we can work on without affecting the initial list.
Creating another list from the first one and modifying the second one makes it so we are not changing the original list and therefore stuff works.
It's "just" computationally inefficient.

Edit: Okay so I realize now that I could update the initial list with the X of "for x, X in enumerate(blah)" instead of pointing to the original list with all the indices like I was doing. I guess it's gonna clean up my code quite a bit.