Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Walrus Operator Doesn't Assign Variable?

Playing with the walrus operator, I have this implementation of merge sort:

def mergesort(array):
    if len(array) == 1:
        output = array
    else:
        pivot = len(array) // 2
        left = mergesort(array[pivot:])
        right = mergesort(array[:pivot])
        output = []
        while (l := len(left)) or (r := len(right)):
            if l and r and left[0] < right[0]:
                output.append(left.pop(0))
            elif r:
                output.append(right.pop(0))
            else:
                output.append(left.pop(0))
        
    return output

mergesort([66, 93, 85, 46, 56, 88, 56, 75, 55, 99, 87])

But this returns the error UnboundLocalError: local variable 'r' referenced before assignment:

---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
/tmp/ipykernel_134/1678992391.py in <module>
----> 1 mergesort(array)

/tmp/ipykernel_134/4030760045.py in mergesort(array)
      5     else:
      6         pivot = len(array) // 2
----> 7         left = mergesort(array[pivot:])
      8         right = mergesort(array[:pivot])
      9         

...

/tmp/ipykernel_134/4030760045.py in mergesort(array)
     10         output = []
     11         while (l := len(left)) or (r := len(right)):
---> 12             if l and r and left[0] < right[0]:
     13                 output.append(left.pop(0))
     14             elif r:

UnboundLocalError: local variable 'r' referenced before assignment

Why isn’t r included in my for loop, while l is?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Boolean OR or is lazy, so when l turns out to be true, (r := len(right)) doesn’t even get executed.

You could use the non-lazy bitwise OR | in this case, although it’s a bit of an abuse.

Or just use the truth value of the lists instead of their lengths:

        while left or right:
            if left and right and left[0] < right[0]:
                output.append(left.pop(0))
            elif right:
                output.append(right.pop(0))
            else:
                output.append(left.pop(0))

Btw better use <= instead of <, so that it’s a stable sort as mergesort ought to be.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading