Bucket Sort for 3 digits

Question:

I have this function that sorts a List of integers using binsort (bucketsort), but it only works if the integers are only 1 digit. For example I input the array [[1,4,2], [6,4,2], [1,4,1]] and the output is [[1,4,1] , [1,4,2], [6,4,2]].

But when I input an array that has a number with <1 digits, I get a "list index out of range." For example, the following array gives me an error, [[22,11,1], [22,13,4]].

How do I fix my function so that it will look at each number twice (first pass looking at the ones place and putting it into the correct bin, then the second and final pass looking at the tens place and moving it to the correct bin) and put them into the correct bin at the end after looking at the tens place?

def binsort(a):
       bins = [a]

       for l in range(len(a[0])-1, -1, -1):
           binsTwo = [[] for _ in range(10)]
           for bin in bins:
               for e in bin:
                   binsTwo[e[l]].append(e)
           bins = binsTwo
    
       return [e for bin in bins for e in bin]

Sorry if this was confusing, I’ll try to expand on it if there are any questions. Thanks for the help.

Asked By: KJC_

||

Answers:

def bucketsort(a):
    # Create empty buckets
    buckets = [[] for _ in range(10)]
    # Sort into buckets
    for i in a:
        buckets[i].append(i)
    # Flatten buckets
    a.clear()
    for bucket in buckets:
        a.extend(bucket)
    return a
Answered By: Tomward Matthias

You wrote that you need a "function that sorts a List of integers", but in your code you pass a list of lists to binsort. This only makes sense if those sublists represent digits of a number. It makes no more sense when these digits are no single digits anymore. Either:

  • You sort a list of integers like [142, 642, 141], or
  • You sort a list of lists of digits, like [[1,4,2], [6,4,2], [1,4,1]], where each sublist is a digit-by-digit representation of an integer

Mixing both representations of integers makes little sense.

Here is how you would do it when using the first representation:

def binsort(a):
    if not a:  # Boundary case: list is empty
        return a
    bins = [[], a]
    power = 1
    while len(bins[0]) < len(a):  # while there could be more digits to binsort by
        binsTwo = [[] for _ in range(10)]
        for bin in bins:
            # Distribute the numbers in the new bins according to i-th digit (power)
            for num in bin:
                binsTwo[num // power % 10].append(num)
        # Prepare for extracting next digit
        power *= 10 
        bins = binsTwo
    return bins[0]

If you use the second representation (list of lists of single digits), then your code is fine, provided you add a check for an empty input list, which is a boundary case.

def binsort(a):
    if not a:  # Boundary case: list is empty
        return a
    bins = [a]
    for i in range(len(a[0]) - 1, -1, -1): # For each digit
        binsTwo = [[] for _ in range(10)]
        for bin in bins:
            # Distribute the numbers in the new bins according to i-th digit
            for digits in bin:
                binsTwo[digits[i]].append(digits)
        # Prepare for extracting next digit
        bins = binsTwo

    return [digits for bin in bins for digits in bin]

But again, you should not try to "solve" the case where you have sublists that consist of multi-digit numbers. Reconsider why you think you need support for that, because it seems like you have mixed two input formats — as I explained above.

Answered By: trincot