0

So I have a list containing a number of elements, each of which are sublists containing two elements; a character and a number. Example:

unordered_list = [["A", 5], ["B", 3], ["C", 10], ["D", 0]]

I have a bubble sort function that orders the sublists in descending order, according to the value in index 1 of each sublist.

def list_sort(n):

    ordered = False
    passes = 0
    while not ordered:
        passes += 1
        ordered = True
        for i in range(0, len(n)-passes):
            if n[i][1] < n[i+1][1]:
                n[i], n[i+1] = n[i+1], n[i]
                ordered = False
    return n

The function works just fine, it's just that if I pass my unordered_list variable into the function in an assignment, ie;

sorted_list = list_sort(unordered_list)
sorted_list --> [["C", 10], ["A", 5], ["B", 3], ["D", 0]]

The sorted_list contains the results I'd expect, however the unsorted_list passed into the function is also ordered after the function call, which is not what I'd expect, as surely only the local variable n in the function and the sorted_list variable should be changed?

What's going on here?

Jckxxlaw
  • 391
  • 1
  • 4
  • 12

2 Answers2

1

n continues to reference the original list, and since n is a mutable object, modifying via the reference will modify the referenced object.

You need to create a copy of the original list.

You can do this by slicing, before mutating the list:

def list_sort(n_original):
    n = n_original[:]
    # your code
    return n

n_original[:] is a shallow copy of list n_original which is synonymous to doing n_original.copy(). If you choose to be more verbose with the copy operation, you can use the builtin copy module.

from copy import copy

def list_sort(n_original):
    n = copy(n_original)
    # your code
    return n

For more on copying and their properties you can look at this: What exactly is the difference between shallow copy, deepcopy and normal assignment operation?

Community
  • 1
  • 1
Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
  • I'm still confused as to why the global list is changed, when n is a local reference ? – Jckxxlaw Jul 01 '16 at 13:16
  • Also, what is the purpose of the [:] in the assignment of n? – Jckxxlaw Jul 01 '16 at 13:17
  • @BrandonEdwards if you don't use the slicing, you don't actually create a new list but rather a new way of accessing the old one, a new way to reference it. – Ma0 Jul 01 '16 at 13:18
  • @BrandonEdwards `n` is a reference to the original list, not just a local reference. You will find this SO thread interesting: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference – Moses Koledoye Jul 01 '16 at 13:25
-1

Here's another way to sort it while leaving the original unchanged:

unordered_list = [["A", 5], ["B", 3], ["C", 10], ["D", 0]]

sorted_list = sorted(unordered_list, key=lambda x: x[1], reverse=True)

print(sorted_list)
# -> [['C', 10], ['A', 5], ['B', 3], ['D', 0]]

print(unordered_list)
# -> [['A', 5], ['B', 3], ['C', 10], ['D', 0]]
Alec
  • 1,399
  • 4
  • 15
  • 27
  • 1
    I think he wants to implement the algorithm by himself... –  Jul 01 '16 at 13:21
  • That makes sense, just thought I'd leave this alternative here in case :) – Alec Jul 01 '16 at 13:25
  • What's the 2nd parameter of that sorted function about?? – Jckxxlaw Jul 01 '16 at 13:25
  • 1
    @BrandonEdwards The``key`` is the function based on which you want to do the sorting. x[1] means based on the second value (the number) of every inner list. – Ma0 Jul 01 '16 at 13:32