简体   繁体   中英

How to sort a python list using insertion sort using 2 conditional attributes?

Lets say I want to sort a list that looks like this:

arr = ['45621', '78124', '24613']

The above list stores the IDs for various employees at a company. I don't want to sort based on the IDs alone, but based on attributes that correspond to the IDs, using the following dictionary:

d = {
    '45621' : { 'rating' : 3, 'hours_worked' : 42 },
    '78124' : { 'rating' : 4, 'hours_worked' : 78 },
    '24613' : { 'rating' : 3, 'hours_worked' : 51 }
}

So its something like this: if an employee has a higher rating , his/her ID will come first. However, if 2 employees have the same rating , then we compare the hours_worked , and whoever has worked more will come before the other.

I want to implement an insertion sort myself. Right now, my code looks like this:

def insertionSort(arr):

    for i in range(1, len(arr)):
        key = d[arr[i]]['rating']
        second_key = d[arr[i]]['hours_worked']
        j = i - 1
        while j >= 0 and key < d[arr[j]]['rating']:
            arr[j+1] = arr[j]
            j -= 1
        d[arr[j+1]]['rating'] = key 

    return arr

I cant seem to use the second key for comparisons. And moreover, this simply does not work. Any help?

Please note, I cannot change the nature of the input and the dictionary, and please no answers using the built-in methods.

It's not that you can't use the second key for comparisons, it's that you simply don't.

Also, it would be good (even if you are not using the built-in methods) to mimic their shape, as it just makes sense.

So let's try that:

def insertionSort(arr, key=lambda x: x):

This says the normal comparison is by element itself. Inside the sort, you can basically check key(element1) and compare it with key(element2) .

If you want to just sort some numbers, the default key function is fine: it will return that same number, so it can get compared.

If you want to use eg a name, you can do key=lambda person: person.name .

What to do if you have multiple criteria? Arrays and tuples have an interesting property: they are comparable! The result of the comparison is the comparison of the first element, unless it is equal, in which case the comparison will proceed to the next element. So, (0, 5) < (1, 5) < (1, 7) < (2, 9) . How can we use this?

 key=lambda e_id: (-d[e_id]['rating'], -d[e_id]['hours_worked'])

This key function constructs a tuple consisting of negative rating and hours_worked (negative because that way we sort in reverse, highest to lowest). The sort function does not need to change at all: you just need to implement the normal insertion sort for one criterion: whether key(element1) is larger, smaller or equal than key(element2) .

You should swap items you find out of order, and you should compare the second key when the first key is equal:

def insertionSort(arr):
    for i in range(1, len(arr)):
        key = d[arr[i]]['rating']
        second_key = d[arr[i]]['hours_worked']
        j = i - 1
        while j >= 0 and key > d[arr[j]]['rating'] or key == d[arr[j]]['rating'] and second_key > d[arr[j]]['hours_worked']:
            arr[j+1], arr[j] = arr[j], arr[j+1]
            j -= 1
        d[arr[j+1]]['rating'] = key
    return arr

so that:

insertionSort(arr)

returns:

['78124', '24613', '45621']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM