10

I was looking a lot and reading a lot of question, but I cannot figure out how to give two arguments to the key of sort method, so I can make a more complex comparison.

Example:

class FruitBox():
  def __init__(self, weigth, fruit_val):
    self.weigth = weigth
    self.fruit_val = fruit_val

I want to compare the FruitBox by fruit_val, but! Also they box heavier are bigger than others.

So it would be:

f1 = FruitBox(2,5)
f2 = FruitBox(1,5)
f3 = FruitBox(2,4)
f4 = FruitBox(3,4)

boxes = [f1,f2,f3,f4]
boxes.sort(key = ???) # here is the question

Expected result: => [FruitBox(2,4),FruitBox(3,4),FruitBox(1,5),FruitBox(2,5)]

Is there a way to send a function with 2 arguments, when I do it something like

def sorted_by(a,b):
  #logic here, I don't know what will be yet

and I do

boxes.sort(key=sorted_by)

It throws:

Traceback (most recent call last):
  File "python", line 15, in <module>
TypeError: sort_by_b() missing 1 required positional argument: 'b'

How can I give Two Arguments to the key of sort?

1

4 Answers 4

20

This answer is dedicated to answering:

How can I give Two Arguments to the key of sort?


The old style compare way to sort is gone in Python 3, as in Python 2 you would do:

def sorted_by(a,b):
    # logic here
    pass

boxes.sort(cmp=sorted_by)

But if you must use it Python 3, it’s still there, but in a module, functools, it’s purpose is to convert the cmp to key:

import functools 
cmp = functools.cmp_to_key(sorted_by)
boxes.sort(key=cmp)

The preferred way to sort is to make a key function that returns a weight for the sorting to base on. See Francisco’s answer.

Sign up to request clarification or add additional context in comments.

Comments

13

If you want to sort using two keys, you can do it like this (I suppose you want to sort first by fruit_val then by weight:

boxes.sort(key=lambda x: (x.fruit_val, x.weigth))

Comments

5

The docs, section on Odd and Ends says:

The sort routines are guaranteed to use __lt__() when making comparisons between two objects. So, it is easy to add a standard sort order to a class by defining an __lt__() method.

In your example that translates to adding the __lt__() to your FruitBox class:

class FruitBox():
    def __init__(self, weigth, fruit_val):
        self.weigth = weigth
        self.fruit_val = fruit_val

    def __lt__(self, other):
        # your arbitrarily complex comparison here:
        if self.fruit_val == other.fruit_val:
             return self.weight < other.weight
        else:
             return self.fruit_val < other.fruit_val

        # or, as simple as:
        return (self.fruit_val, self.weight) < (other.fruit_val, other.weight)

Then use it simply like this:

sorted(fruitbox_objects)

Comments

0

You can sort using the key parameter with the fruit_val member variable:

boxes = [f1,f2,f3,f4]
boxes.sort(key=lambda x:x.fruit_val)
print([i.__dict__ for i in boxes])

Output:

[{'fruit_val': 4, 'weigth': 2}, {'fruit_val': 4, 'weigth': 3}, {'fruit_val': 5, 'weigth': 2}, {'fruit_val': 5, 'weigth': 1}]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.