How do I sort a list of dictionaries by a value of the dictionary?

后端 未结 18 2788
半阙折子戏
半阙折子戏 2020-11-21 04:06

I have a list of dictionaries and want each item to be sorted by a specific value.

Take into consideration the list:

[{\'name\':\'Homer\', \'age\':39},         


        
相关标签:
18条回答
  • 2020-11-21 04:53

    Here is the alternative general solution - it sorts elements of a dict by keys and values.

    The advantage of it - no need to specify keys, and it would still work if some keys are missing in some of dictionaries.

    def sort_key_func(item):
        """ Helper function used to sort list of dicts
    
        :param item: dict
        :return: sorted list of tuples (k, v)
        """
        pairs = []
        for k, v in item.items():
            pairs.append((k, v))
        return sorted(pairs)
    sorted(A, key=sort_key_func)
    
    0 讨论(0)
  • 2020-11-21 04:53

    If performance is a concern, I would use operator.itemgetter instead of lambda as built-in functions perform faster than hand-crafted functions. The itemgetter function seems to perform approximately 20% faster than lambda based on my testing.

    From https://wiki.python.org/moin/PythonSpeed:

    Likewise, the builtin functions run faster than hand-built equivalents. For example, map(operator.add, v1, v2) is faster than map(lambda x,y: x+y, v1, v2).

    Here is a comparison of sorting speed using lambda vs itemgetter.

    import random
    import operator
    
    # Create a list of 100 dicts with random 8-letter names and random ages from 0 to 100.
    l = [{'name': ''.join(random.choices(string.ascii_lowercase, k=8)), 'age': random.randint(0, 100)} for i in range(100)]
    
    # Test the performance with a lambda function sorting on name
    %timeit sorted(l, key=lambda x: x['name'])
    13 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    # Test the performance with itemgetter sorting on name
    %timeit sorted(l, key=operator.itemgetter('name'))
    10.7 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    # Check that each technique produces the same sort order
    sorted(l, key=lambda x: x['name']) == sorted(l, key=operator.itemgetter('name'))
    True
    

    Both techniques sort the list in the same order (verified by execution of the final statement in the code block), but the first one is a little faster.

    0 讨论(0)
  • 2020-11-21 04:55

    If you do not need the original list of dictionaries, you could modify it in-place with sort() method using a custom key function.

    Key function:

    def get_name(d):
        """ Return the value of a key in a dictionary. """
    
        return d["name"]
    

    The list to be sorted:

    data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
    

    Sorting it in-place:

    data_one.sort(key=get_name)
    

    If you need the original list, call the sorted() function passing it the list and the key function, then assign the returned sorted list to a new variable:

    data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
    new_data = sorted(data_two, key=get_name)
    

    Printing data_one and new_data.

    >>> print(data_one)
    [{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
    >>> print(new_data)
    [{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
    
    0 讨论(0)
  • 2020-11-21 04:57
    my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
    
    my_list.sort(lambda x,y : cmp(x['name'], y['name']))
    

    my_list will now be what you want.

    Or better:

    Since Python 2.4, there's a key argument is both more efficient and neater:

    my_list = sorted(my_list, key=lambda k: k['name'])
    

    ...the lambda is, IMO, easier to understand than operator.itemgetter, but your mileage may vary.

    0 讨论(0)
  • 2020-11-21 04:59

    It may look cleaner using a key instead a cmp:

    newlist = sorted(list_to_be_sorted, key=lambda k: k['name']) 
    

    or as J.F.Sebastian and others suggested,

    from operator import itemgetter
    newlist = sorted(list_to_be_sorted, key=itemgetter('name')) 
    

    For completeness (as pointed out in comments by fitzgeraldsteele), add reverse=True to sort descending

    newlist = sorted(l, key=itemgetter('name'), reverse=True)
    
    0 讨论(0)
  • 2020-11-21 05:00

    If you want to sort the list by multiple keys, you can do the following:

    my_list = [{'name':'Homer', 'age':39}, {'name':'Milhouse', 'age':10}, {'name':'Bart', 'age':10} ]
    sortedlist = sorted(my_list , key=lambda elem: "%02d %s" % (elem['age'], elem['name']))
    

    It is rather hackish, since it relies on converting the values into a single string representation for comparison, but it works as expected for numbers including negative ones (although you will need to format your string appropriately with zero paddings if you are using numbers).

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