Как отсортировать список словарей по значению словаря?

Взято из Путаница с разбором Enum

Это было решение со стороны людей, создавших .NET. Перечисление поддерживается другим типом значения (int, short, byte и т. Д.), И поэтому он может фактически иметь любое значение, которое действительно для этих типов значений.

Я лично не поклонник того, как это работает, поэтому я сделал ряд полезных методов:

/// 
/// Utility methods for enum values. This static type will fail to initialize 
/// (throwing a ) if
/// you try to provide a value that is not an enum.
/// 
/// An enum type. 
public static class EnumUtil
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // Throw Exception on static initialization if the given type isn't an enum.
        Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
    }

    /// 
    /// In the .NET Framework, objects can be cast to enum values which are not
    /// defined for their type. This method provides a simple fail-fast check
    /// that the enum value is defined, and creates a cast at the same time.
    /// Cast the given value as the given enum type.
    /// Throw an exception if the value is not defined for the given enum type.
    /// 
    /// 
    /// 
    /// 
    /// If the given value is not a defined value of the enum type.
    /// 
    /// 
    public static T DefinedCast(object enumValue)

    {
        if (!System.Enum.IsDefined(typeof(T), enumValue))
            throw new InvalidCastException(enumValue + " is not a defined value for enum type " +
                                           typeof (T).FullName);
        return (T) enumValue;
    }

    /// 
    /// 
    /// 
    /// 
    /// 
    public static T Parse(string enumValue)
    {
        var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
        //Require that the parsed value is defined
        Require.That(parsedValue.IsDefined(), 
            () => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}", 
                enumValue, typeof(T).FullName)));
        return parsedValue;
    }

    public static bool IsDefined(T enumValue)
    {
        return System.Enum.IsDefined(typeof (T), enumValue);
    }

}


public static class EnumExtensions
{
    public static bool IsDefined(this T enumValue)
        where T : struct, IConvertible
    {
        return EnumUtil.IsDefined(enumValue);
    }
}

Таким образом, я могу сказать:

if(!sEnum.IsDefined()) throw new Exception(...);

... или:

EnumUtil.Parse(s); // throws an exception if s is not a defined value.

Редактировать

. Помимо объяснений, приведенных выше, вы должны понимать, что версия Enum .NET имеет более C-вдохновленный шаблон, чем Java-вдохновленный. Это позволяет иметь «бит флаг» перечисления , которые могут использовать двоичные паттерны, чтобы определить, активен ли конкретный «флаг» в значении перечисления. Если вам нужно было определить все возможные комбинации флагов (т. Е. MondayAndTuesday, MondayAndWednesdayAndThursday), это было бы очень утомительно. Поэтому иметь возможность использовать неопределенные значения перечисления может быть очень удобно. Это просто требует немного дополнительной работы, когда вам нужно отказоустойчивое поведение для типов перечислений, которые не используют эти трюки.

1638
задан 9 revs, 6 users 72% 26 October 2018 в 13:56
поделиться

9 ответов

Это может посмотреть более чистое использование ключа вместо этого cmp:

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

или поскольку J.F.Sebastian и предложенные другие,

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

Для полноты (как указано в комментариях fitzgeraldsteele), добавляют reverse=True к виду, убывающему

newlist = sorted(l, key=itemgetter('name'), reverse=True)
2167
ответ дан Dave Lasley 26 October 2018 в 13:56
поделиться
import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

'ключ' привык к виду произвольным значением, и 'itemgetter' устанавливает то значение к атрибуту 'имени' каждого объекта.

26
ответ дан efotinis 26 October 2018 в 13:56
поделиться

Необходимо реализовать собственную функцию сравнения, которая сравнит словари значениями ключей имени. См. Сортировать МИНИ-КАК К от PythonInfo Wiki

15
ответ дан Matej 26 October 2018 в 13:56
поделиться

Я предполагаю, что Вы имели в виду:

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

Это было бы отсортировано как это:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
18
ответ дан Bartosz Radaczyński 26 October 2018 в 13:56
поделиться
my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

my_list.sort(lambda x,y : cmp(x['name'], y['name']))

my_list теперь будет тем, что Вы хотите.

(3 года спустя) Отредактированный для добавления:

новое key аргумент более эффективен и более опрятен. Лучший ответ теперь похож:

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

... лямбда, IMO, легче понять, чем operator.itemgetter, но YMMV.

44
ответ дан pjz 26 October 2018 в 13:56
поделиться
import operator

Для сортировки списка словарей ключом ='name':

list_of_dicts.sort(key=operator.itemgetter('name'))

Для сортировки списка словарей ключом ='age':

list_of_dicts.sort(key=operator.itemgetter('age'))
130
ответ дан cedbeu 26 October 2018 в 13:56
поделиться

Вы могли использовать пользовательскую функцию сравнения, или Вы могли передать в функции, которая вычисляет пользовательский ключ сортировки. Это обычно более эффективно, поскольку ключ только вычисляется однажды на объект, в то время как функция сравнения была бы вызвана намного больше раз.

Вы могли сделать это этот путь:

def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey)

, Но стандартная библиотека содержит универсальную стандартную программу для получения объектов произвольных объектов: itemgetter. Так попробуйте это вместо этого:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))
16
ответ дан Owen 26 October 2018 в 13:56
поделиться

Я был большим поклонником фильтра w/лямбда однако, это не наилучший вариант если Вы рассматривающий временную сложность

опция

list_to_sort.sort(key=operator.itemgetter('name'))
#edits the list, does not return a new list

Second опции

sorted_list = sorted(list_to_sort, key= lambda x: x['name'])
# returns list of values

First Быстрое сравнение исполнительных времен

# First option
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" "sorted_l = sorted(list_to_sort, key=lambda e: e['name'])"

1 000 000 циклов, лучших из 3: 0,736 мкс за цикл

# Second option 
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" -s "import operator" "list_to_sort.sort(key=operator.itemgetter('name'))"

1 000 000 циклов, лучших из 3: 0,438 мкс за цикл

0
ответ дан Bejür 4 October 2019 в 07:29
поделиться
  • 1
    спасибо, that' s хорошее прямое для выполнения то, в чем я нуждаюсь. – Idr 12 May 2011 в 09:26

Если вы хотите отсортировать список по нескольким ключам, вы можете сделать следующее:

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']))

Это довольно хакерский метод, поскольку он основан на преобразовании значений в одно строковое представление для сравнение, но оно работает должным образом для чисел, включая отрицательные (хотя вам нужно будет соответствующим образом отформатировать строку с нулевым заполнением, если вы используете числа)

46
ответ дан 22 November 2019 в 20:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: