Home > Software design >  How to get a list of dictionaries sorted by three criteria
How to get a list of dictionaries sorted by three criteria

Time:09-17

I want to get a list sorted accordingly to the following rules persons.sort(key = lambda p: (abs(p["height"] - 180), p["weight"]==75, p["weight"])) i.e. I need it to get sorted firstly by its closeness to the height 180, then all of the weight values which are equal to 75, and then I want them to be sorted ascendingly by its weight...

I came up with the following code, which is not working...

def get_ordered_list(persons):
    persons.sort(key = lambda p: p["name"] )
    persons.sort(key = lambda p: (abs(p["height"] - 180), p["weight"]==75, p["weight"]))
    return persons

For the following sample data, for instance,

array = [{"name": "Guido Batista", "height": 195, "weight": 110},
    {"name":"Heitor Tostes", "height": 180, "weight": 75},
    {"name":"Bruno Costa", "height": 180, "weight": 75},
    {"name":"Joao Kleber", "height": 180, "weight": 65},
    {"name":"Rafael Rodrigues", "height": 165, "weight": 110},
    {"name":"Ricardo Neto", "height": 170, "weight": 70},
    {"name":"Juca Carvalho", "height": 180, "weight": 77}]
    

I need to get the list sorted as such:

[
      {"name":"Bruno Costa", "height": 180, "weight": 75},
      {"name":"Heitor Tostes", "height": 180 , "weight": 75},
      {"name":"Joao Kleber", "height": 180, "weight": 65},
      {"name":"Juca Carvalho", "height": 180, "weight": 77},
      {"name":"Ricardo Neto", "height": 170, "weight": 70},
      {"name": "Guido Batista", "height": 195, "weight": 110},
      {"name":"Rafael Rodrigues", "height": 165, "weight": 110},
]

CodePudding user response:

This is happening because False is a lower value than True. Use

 persons.sort(key = lambda p: (abs(p["height"] - 180), p["weight"]!=75, p["weight"]))

changing the comparison for the "weight" key.

CodePudding user response:

This would give the desired result without complicating further:

persons.sort(key = lambda p: (abs(p["height"] - 180), not(p["weight"]==75), p["weight"]))

By default the sorting order is ascending. And the last piece of puzzle is this (from doc)

Booleans: These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of plain integers, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively

In the ascending order 0 comes before 1 and that's why this line posted above would fix the issue.

CodePudding user response:

Try:

array = [
    {"name": "Guido Batista", "height": 195, "weight": 110},
    {"name": "Heitor Tostes", "height": 180, "weight": 75},
    {"name": "Bruno Costa", "height": 180, "weight": 75},
    {"name": "Joao Kleber", "height": 180, "weight": 65},
    {"name": "Rafael Rodrigues", "height": 165, "weight": 110},
    {"name": "Ricardo Neto", "height": 170, "weight": 70},
    {"name": "Juca Carvalho", "height": 180, "weight": 77},
]

array = sorted(
    array,
    key=lambda p: (
        abs(p["height"] - 180),
        p["weight"] != 75,
        p["name"],
        -p["weight"],
    ),
)
print(array)

Prints:

[
    {"name": "Bruno Costa", "height": 180, "weight": 75},
    {"name": "Heitor Tostes", "height": 180, "weight": 75},
    {"name": "Joao Kleber", "height": 180, "weight": 65},
    {"name": "Juca Carvalho", "height": 180, "weight": 77},
    {"name": "Ricardo Neto", "height": 170, "weight": 70},
    {"name": "Guido Batista", "height": 195, "weight": 110},
    {"name": "Rafael Rodrigues", "height": 165, "weight": 110},
]
  • Related