user3277633
user3277633

Reputation: 1923

python list is not copying

In the following subset problem, I'm trying to make a copy of a list object

def findFourPlus(itemCount, seq, goal):
    goalDifference = float("inf")
    closestPartial = []
    subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial=[])
    print(closestPartial)


def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):
    s = sum(partial)

    # check if the partial sum is equals to target
    if(len(partial) == itemCount):
        if s == goal:
            print(partial)
    else:
        if( abs(goal - s) < goalDifference):
            goalDifference = abs(goal - s)
            print(goalDifference)
            print(partial)
            print(closestPartial)
            closestPartial = copy.deepcopy(partial)        

for i in range(len(seq)):
    n = seq[i]
    remaining = seq[i+1:]
    subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n])

in the subset function, I am trying to make a copy of the partial list to closestPartial. I've tried

closestPartial = partial
closestPartial = list[:]
closestPartial = list(partial)
closestPartial = copy.copy(partial)
closestPartial = copy.deepcopy(partial)

but in the end all of them seems to be futile. closestPartial remains to be an empty list (which is what I initiated to) for some reason

Upvotes: 0

Views: 88

Answers (2)

PM 2Ring
PM 2Ring

Reputation: 55489

I suspect that your goalDifference is suffering from the same problem, if you change it in a function and then expect the changed value to somehow get back to the calling function.

Here's some (Python 2 style) code to illustrate what's happening:

#! /usr/bin/env python

def testA(update_func):
    seq = []
    num = 1
    for _ in range(5):
        newnum = update_func(seq, num)
        print 'testA:  ', num, seq, newnum
    print

def testB(update_func):
    seq = []
    num = 1
    for _ in range(5):
        num = update_func(seq, num)
        print 'testB:  ', num, seq
    print


def update0(seq, num):
    #This creates a new list
    seq = seq + [num]
    num = num + 1
    print 'update0:', num, seq
    return num

def update1(seq, num):
    #This updates the existing list
    seq.append(num)
    num += 1
    print 'update1:', num, seq
    return num

def update2(seq, num):
    #This updates the existing list
    seq[:] = seq + [num]
    num += 1
    print 'update2:', num, seq
    return num

def update3(seq, num):
    #This updates the existing list
    seq += [num]
    num += 1
    print 'update2:', num, seq
    return num


update_funcs = (update0, update1, update2, update3)
for f in update_funcs:
    testA(f)

print '------\n'

for f in update_funcs:
    testB(f)

Stack Overflow member Ned Batchelder's article Facts and myths about Python names and values has a good explanation, with cute diagrams.

Upvotes: 0

tdelaney
tdelaney

Reputation: 77367

You are passing closestPartial in as a parameter, so the only thing that will work is an inplace update of its list. All of the examples you give replace the list that was in closestPartial with a new list. But since it wasn't the list you passed in, it doesn't update the real list.

Try:

closestPartial[:] = partial

You can get a feel for the problem by printing the list id before and after the operation.

print id(closestPartial)
...some operation
print id(closestPartial)

if the id changes, that means you created a new list and didn't update the one passed in.

EDIT

Seems I need a better explanation... when you call subset_sum, it creates a local variable called closestPartial that references whatever was passed in as a parameter, in this case a list known to the caller as closestPartial. You now have two variables pointing to the same list. If you reassign the variable, like in closestPartial = partial, those two variables now point to different lists. You didn't update the caller's pointer, you just changed the local variable. Instead, if you don't reassign, changes you make to the one list referenced by both variables are seen by the caller as well - because its the same list.

Upvotes: 1

Related Questions