George
George

Reputation: 27

Why are elements of my array being over written?

I have written a simple function in Python which aims to find, if from two elements a and b, one can be obtained from another by swapping at most one pair of elements in one of the arrays.

This is my function:

def areSimilar(a, b):
    test = 0
    for i in range(len(b)):
        for j in range(len(b)):
            b2 = b
            b2[i] = b[j]
            b2[j] = b[i]
            if a == b2:
                test = 1
    return(test==1)

The issue is that upon inspecting b, it has changed even though I don't actually perform any calculations on b - what's going on!!??

Upvotes: 0

Views: 52

Answers (2)

norok2
norok2

Reputation: 26896

(EDITED: to better address the second point)

There are two issues with your code:

  • When you do b2 = b this just creates another reference to the underlying object. If b is mutable, any change made to b2 will be reflected in b too.
  • When a single swapping suffices there is no need to test further, but if you keep on looping the test will be successful again with i and j swapped, so test condition is hit either never or (at least -- depending on the amount of duplicates) twice. While this would not lead to incorrect results, it would normally be regarded as an error in the logic.

To fix your code, you could just create a copy of b. Assuming that by Python arrays you actually mean Python lists one way of doing it would be to create a new list every time by replacing b2 = b with b2 = list(b). A more efficient approach is to perform the swapping on b itself (and swap back):

def are_similar(a, b):
    for i in range(len(b)):
        for j in range(len(b)):
            b[i], b[j] = b[j], b[i]
            if a == b:
                b[i], b[j] = b[j], b[i]  # swap back
                return True
            else:
                b[i], b[j] = b[j], b[i]  # swap back
    return False


print(are_similar([1, 1, 2, 3], [1, 2, 1, 3]))
# True
print(are_similar([1, 1, 2, 3], [3, 2, 1, 1]))
# False

By contrast, you can see how inefficient (while correct) the copying-based approach is:

def are_similar2(a, b):
    for i in range(len(b)):
        for j in range(len(b)):
            b2 = list(b)
            b2[i] = b[j]
            b2[j] = b[i]
            if a == b2:
                return True
    return False


print(are_similar2([1, 1, 2, 3], [1, 2, 1, 3]))
# True
print(are_similar2([1, 1, 2, 3], [3, 2, 1, 1]))
# False

with much worse timings, even on relatively small inputs:

a = [1, 1, 2, 3] + list(range(100))
b = [1, 2, 1, 3] + list(range(100))
%timeit are_similar(a, b)
# 10000 loops, best of 3: 22.9 µs per loop
%timeit are_similar2(a, b)
# 10000 loops, best of 3: 73.9 µs per loop

Upvotes: 1

Roshin Raphel
Roshin Raphel

Reputation: 2699

I would got with Sadap's code, but if you want to copy, use :

import copy
def areSimilar(a, b):
    test = 0
    for i in range(len(b)):
        for j in range(len(b)):
            b2 = copy.deepcopy(b)
            b2[i] = copy.deepcopy(b[j])
            b2[j] = copy.deepcopy(b[i])
            if a == b2:
                test = 1
    if test == 1:
        return True
    else:
        return False

Upvotes: 0

Related Questions