1

I've got a problem. In python I've got an function, which should print the longest path. The function works, if I use a list like [[1,2,3,4,5][1,2,3,4,5]] but if I use list like [x] for x in range(5)]*2, or any other list like that. (I don't know what is this called in python, but if I have list like [vale]*something), the code doesn't work. So, my question is, how can I make new list, without any references. Deepcopy or [:] doesn't work, because references inside list, are still there. But I don't know how to copy just values, without references. :) Thanks.

def naj_narascajoca(vrtek):


    visina = len(vrtek)
    sirina = len(vrtek[0])

    vrt = []
    vrt.append([-1]*(sirina+2))
    for greda in vrtek:
        greda.insert(0,-1)
        greda.append(-1)
        vrt.append(greda)

    vrt.append([-1]*(sirina+2))


    for i in vrt:
        print(i)


    pot = ""
    maximal = 0
    je_vecja = True
    x = 1
    y = 1
    max_odlocitev = 0
    while je_vecja == True:

        print("--------------",vrt[x][y],"-----------------")

        vre_left = vrt[x][y-1]
        vre_right = vrt[x][y+1]
        vre_up = vrt[x-1][y]
        vre_down = vrt[x+1][y]
        sez = sorted([vre_down,vre_left, vre_right, vre_up])
        for i in sez:
            if i > maximal:
                max_odlocitev = i;
                break
        #max_odlocitev = max(vrt[x][y-1],vrt[x][y+1], vrt[x+1][y], vrt[x-1][y])
        if maximal < max_odlocitev:
                maximal = max_odlocitev
                if vrt[x][y-1] == maximal:
                    pot += "L"
                    y -=1
                elif vrt[x][y+1] == maximal:
                    pot += "R"
                    y+=1
                elif vrt[x+1][y] == maximal:
                    pot += "D"
                    x+=1
                elif vrt[x-1][y] == maximal:
                    pot += "U"
                    x-=1


        else:
            je_vecja = False

    print(pot)

vrt = [[1,3,3,8,5,4,2,1,5,6],
    [2,4,3,3,6,8,1,3,5,6],
    [4,5,6,4,7,4,3,6,4,7],
    [2,8,7,0,0,7,4,7,8,0],
    [2,3,4,7,0,8,7,6,3,8],
    [3,7,9,0,8,5,3,2,3,4],
    [1,5,7,7,6,4,2,3,5,6],
    [0,6,3,3,6,8,0,6,7,7],
    [0,1,3,2,8,0,0,0,0,0],
    [3,1,0,3,6,7,0,5,3,1],
    [1,3,5,7,0,8,6,5,3,1],
    [3,6,3,1,3,5,8,7,5,1],
    [4,3,6,0,0,8,4,7,5,3],
    [3,5,6,8,6,3,1,3,5,2]]

#naj_narascajoca(vrt)
naj_narascajoca([[x] for x in range(5)]*2)

2 Answers 2

1

Anything like this:

[any mutable objects] * 2

… is explicitly making two references to each mutable object. It doesn't matter how you create the original list, it's the same problem, with the same solution explained in the FAQ: you have to define the list twice. So, instead of this:

[[x] for x in range(5)]*2

… do this:

[[x] for _ in range(2) for x in range(5)]

The reason deepcopy doesn't seem to work is that you're (presumably) using it like this:

copy.deepcopy([[x] for x in range(5)]*2)

And deepcopy is smarter than you think. It's making a deep copy of your structure of 2 references to the same list of 5 lists. So you end up with 5 new lists, a new list of 5 lists, and 2 new references to that new list.

But it can do what you want. You just need to copy the list before putting the two copies together:

>>> a = [[x] for x in range(5)]
>>> b = [copy.deepcopy(a), copy.deepcopy(a)]
>>> # or [copy.deepcopy(a) for _ in range(2)]
>>> b[0] is b[1]
False
>>> b[0][0] is b[1][0]
False

Or, alternatively, map the copy over the list of two references, so they each get copied individually:

>>> b = [copy.deepcopy(x) for x in a*2]
>>> b[0][0] is b[1][0]
False
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for this, but the problem is, that I don't know what type of list I will get. The list may be given like that [any mutable objects] * 2 or, like [[1,2,3,4][1,2,2,2]]... or anything else. So, I would like to make new list, but copy just values, not references. Is that possible?
I can't edit last comment. I will add some more explanation. And, if I get a list, let's call it abc and abc[0] is abc[1] I want new list, for example defg[], that will be defg[0] is not defg[1] but abc[0] == defg[0] and same for [1]. So, same values, but no references, even in inner lists.
@MatejMohar: I think I know what you mean. Let me edit the answer.
Thank you! This is what I was lookig for! Uh, now I understand how copying works:)
0

When you use *2 on a list, you're not making copies of the list as you've discovered - you're making two references to the exact same list. You can use another level of list comprehension to get what you need.

[[[x] for x in range(5)] for y in range(2)]

Or perhaps the problem is that you were getting a list of lists in the inner part when you wanted just a single list 1-5:

[list(range(1, 6)) for x in range(2)]

4 Comments

The comprehension of comprehensions doesn't give you the right list; you get [[[0], [1], [2], [3], [4]], [[0], [1], [2], [3], [4]]] instead of [[0], [1], [2], [3], [4], [0], [1], [2], [3], [4]]. You need a single nested comprehension (as in my answer), unless you want to flatten it after the fact (e.g., list(chain.from_iterable(…))).
@abarnert, that's why I presented the second solution because I thought that's probably closer to what was intended.
Hi! Thanks for answer. I answer on @abarnet answer, so please, take a look :)
@MarkRansom: The second solution gives [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]], which is also a different shape than the OP's original.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.