Python: sort an array of dictionaries with custom comparator?

后端 未结 8 1237

I have the following Python array of dictionaries:

myarr = [ { \'name\': \'Richard\', \'rank\': 1 },
{ \'name\': \'Reuben\', \'rank\': 4 },
{ \'name\': \'Reece\'         


        
相关标签:
8条回答
  • 2021-02-08 11:07

    You're myarr binding here doesn't look like valid Python code (and doesn't execute in my interpreter session.

    Rendering that into:

    myarr = {
        'Richard': 1,
        'Reuben': 4,
        'Reece': 0,
        'Rohan': 3,
        'Ralph': 2,
        'Raphael': 0,
        'Robin': 0 }
    

    Gives me something on which I could base an answer.

    The recommended way to do custom sorting in Python is to use the DSU (decorate, sort, undecorate) pattern. If you want to sort a dictionary by values then that looks something like:

    keys_sorted_by_val = [ x[1] for x in sorted([(v,k) for k,v in myarr.items()])]
    

    ... where (v,k) for k,v in myarr.items() is the expression to decorate; sorted() is, obviously, the sort and the outer x[1] for x in ... is the final undecorate step.

    Obviously this might seem like a sufficiently common requirement that one might which to wrap this up in a function:

    def dict_by_values(d):
        return [ x[1] for x in sorted([(v,k) for k,v in d.items()])]
    

    If you had a collection of object instances that you want to sort by some attribute you can use something like this:

    def sort_by_attr(attr, coll):
        results = list()
        for each in coll:
            assert hasattr(each, attr)
            results.append((getattr(each, attr), each))
        results.sort()
        return [x[1] for x in results]
    

    So if we created a class representing your name/rank data like this:

    class NameRanking(object):
        def __init__(self, name, rank):
            self.name = name
            self.rank = rank
        def __repr__(self):
            return "%s: %s, %s" %(self.__class__, self.name, self.rank)
    

    ... and instantiate a list of those using myarr:

    name_rankings = [ NameRanking(k, v) for k,v in myarr.items() ]

    ... then we could get a sorted copy of that using:

    names_rankings_by_rank = sort_by_attr('rank', name_rankings)
    

    (Yes the assert isn't a good idea here; that's where you would put in your own exception handling or throwing code as appropriate to your application).

    0 讨论(0)
  • 2021-02-08 11:09

    I'd do

     sortedlist = sorted([x for x in myarr if x['rank']], key=lambda x: x['rank']) + [x for x in myarr if not x['rank']]
    

    bit I guess it could be compressed somehow.

    0 讨论(0)
提交回复
热议问题