[Tutor] custom comparator with ordered list

Peter Otten __peter__ at web.de
Mon Jun 26 13:32:39 EDT 2017


Anish Kumar wrote:

> 
>> anish singh wrote:
>> 
>>> I need a custom comparator.
>>> 
>>> dictionary = {a:[b,c], d:[e,f]}
>>> 
>>> If both 'b' and 'e' belong to the same bin
>>> then it should be compared based on 'c' and 'f'.
>>> 
>>> However, I want to also represent the result of the
>>> sorted operation in a ordered dictionary as order is
>>> important.
>>> 
>>> My custom comparator is something like this:
>>> 
>>> 
>>> ''' x and y is a list of two elements each'''
>>> def cmpr(x, y):
>>>    r = 3
>>>    if x[0]//r != y[0]//r:
>>>        return x[0]//r < y[0]//r
>>>    return x[1] < y[1]
>> 
>> This looks like it should be called less() rather than compare() as it
>> doesn't differentiate between the x < y and x == y case.
>> 
>>> Please note it is not exactly comparing the first elements
>>> of the value but checking if they belong to the same bin
>>> and they do then it checks the second element as as shown
>>> above.
>> 
>> The effect should be the same.
> 
> Well no, take the case of [1,100] and [2,0]
> Both belong to same bin suppose then it should
> be sorted based on second index and I would
> expect [2,0] [1,100] as output.
> This is not happening currently with the original
> code I have sent.

I think that is because you do not consider all three cases.
Let's start with a function cmp() modeled after the Python 2 built-in

def cmp(a, b):
    if a < b:
        return -1
    elif a > b:
        return 1
    return 0

Then your comparator could be fixed (I think) as follows

def compare(x, y):
    def bin(a): return a[0] // 3

    result = cmp(bin(x), bin(y))
    if result:
        return result
    return cmp(x[1], y[1])

and that "fixed" version would be equivalent (I think) to

def compare(x, y)
    def key(a): return (a[0] // 3, a[1])

    return cmp((key(x), key(y))

That said, even if you use Python 2 you should use sorted() with a key 
function rather than a comparison -- as shown below. Did that work for you?

>>> Example:
>>> {0:[0, 8], 1:[2, 5], 2:[2, 11], 3:[16, 17], 4:[13, 14], 5:[1, 17],
>>> {6:[17,
>>> 17] }
>>> output should be:
>>> {1:[2, 5], 0:[0, 8], 2:[2, 11], 5:[1, 17], 4:[13, 14], 3:[16, 17],
>>> {6:[17,
>>> 17] }
>> 
>>>>> input = {0:[0, 8], 1:[2, 5], 2:[2, 11], 3:[16, 17], 4:[13, 14], 5:[1,
>> 17], 6:[17,
>> ... 17] }
>>>>> wanted = {1:[2, 5], 0:[0, 8], 2:[2, 11], 5:[1, 17], 4:[13, 14], 3:[16,
>> 17], 6:[17,
>> ... 17] }
>>>>> output = {k: v for k, v in sorted(input.items(), key=lambda x: (x[1]
>> [0]//3, x[1][1]))}
>>>>> assert list(output.items()) == list(wanted.items())
>> 
>> As written it will work with CPython 3.6. However, for compatibility with
>> other versions of Python I recommend that you replace the plain dicts
>> above with collections.OrderedDict instances. Quoting
>> 
>> https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep520
>> 
>> """
>> The order-preserving aspect of this new [dict] implementation is
>> considered an implementation detail and should not be relied upon [...]
>> """




More information about the Tutor mailing list