Сортировка списка словарей по значениям, нечувствительным к регистру, в python 3 [duplicate]

Поскольку второй + оценивается как оператор унарный плюс , такой как

'' + + ' new message'
= '' + (+' new message')
= '' + NaN
= NaN

6
задан SimonSalman 8 September 2009 в 15:56
поделиться

7 ответов

В общем случае вы хотите написать свою функцию извлечения ключей для сортировки; только в особых (хотя и важных) случаях бывает так, что вы можете просто повторно использовать существующее вызываемое для извлечения ключей для вас или просто подключить пару существующих («быстрым и грязным» способом с помощью lambda, поскольку нет встроенный способ выполнения композиции функций.

Если вам часто приходится выполнять эти два вида операций для извлечения ключей (получить элемент и вызвать метод для этого элемента), я предлагаю:

def combiner(itemkey, methodname, *a, **k):
  def keyextractor(container):
    item = container[itemkey]
    method = getattr(item, methodname)
    return method(*a, **k)
  return keyextractor

, поэтому listofdicts.sort(key=combiner('name', 'lower')) будет работать в вашем случае.

Обратите внимание, что в то время как чрезмерное обобщение имеет издержки, со вкусом и умеренным обобщением (оставляя ключ элемента, имя метода и аргументы метода, если таковые имеются , поскольку в этом случае определено время выполнения), как правило, имеет преимущества - одна общая функция, не более сложная, чем дюжина конкретных и специализированных (с экстрактором, методом вызова или и тем, и другим), будет проще в их коде) для поддержания (и, конечно же, намного проще повторного использования!).)

10
ответ дан Benjamin 19 August 2018 в 09:27
поделиться
from functools import partial

def nested_funcs(*funcs):
    return partial(reduce, lambda arg, func: func(arg), funcs)


sorted(list_of_dicts, key=nested_funcs(itemgetter('name'), str.strip, str.lower))
3
ответ дан Alex K 19 August 2018 в 09:27
поделиться

Вероятно, вы должны пойти с лямбдой ради удобочитаемости. Но как интересное исследование функций более высокого порядка, вот расширенная версия q-combinator в Python (также известная как компилятор странных птиц). Это позволяет вам создать новую функцию, составив две функции

 def compose(inner_func, *outer_funcs):
     if not outer_funcs:
         return inner_func
     outer_func = compose(*outer_funcs)
     return lambda *args, **kwargs: outer_func(inner_func(*args, **kwargs))

 from operator import itemgetter, methodcaller
 name_lowered = compose(itemgetter('name'), methodcaller('lower'))
 print(name_lowered( {'name': 'Foo'} ))

. Если вы измените определения внутреннего и внешнего в функции compose, вы получите более традиционный b-combinator (bluebird). Мне больше нравится q-combinator из-за сходства с Unix-каналами.

4
ответ дан Ants Aasma 19 August 2018 в 09:27
поделиться

Лично мне хотелось бы, чтобы в стандартной библиотеке Python было две функции (возможно, в functools):

def compose(*funcs):
    """
    Compose any number of unary functions into a single unary
    function.

    >>> import textwrap
    >>> str.strip(textwrap.dedent(compose.__doc__)) == compose(str.strip, textwrap.dedent)(compose.__doc__)
    True
    """

    compose_two = lambda f1, f2: lambda v: f1(f2(v))
    return reduce(compose_two, funcs)

def method_caller(method_name, *args, **kwargs):
    """
    Return a function that will call a named method on the
    target object with optional positional and keyword
    arguments.

    >>> lower = method_caller('lower')
    >>> lower('MyString')
    'mystring'
    """
    def call_method(target):
        func = getattr(target, method_name)
        return func(*args, **kwargs)
    return call_method

Я реализовал их для собственного использования в jaraco.util.functools .

В любом случае, теперь ваш код достаточно ясен, самодокументирован и прочен (IMO).

lower = method_caller('lower')
get_name = itemgetter('name')
lowered_name = compose(lower, get_name)

list_of_dicts.sort(key=lowered_name)
4
ответ дан Jason R. Coombs 19 August 2018 в 09:27
поделиться

Как насчет этого:

list_of_dicts.sort(key=lambda a: a['name'].lower())
13
ответ дан Nadia Alramli 19 August 2018 в 09:27
поделиться
  • 1
    Я получаю сообщение об ошибке "Not iteratable & quot; – chovy 6 May 2015 в 01:23
def lower_getter(field):
    def _getter(obj):
        return obj[field].lower()
    return _getter

list_of_dicts.sort(key=lower_getter(key_field))
2
ответ дан nosklo 19 August 2018 в 09:27
поделиться
  • 1
    и в качестве плюса он будет автоматически работать как с байтами, так и с юникодными строками. – nosklo 8 September 2009 в 16:09

Это решение будет использовать ваш языковой стандарт вашей системы, а в качестве бонуса он будет сортировать и другие персонажи в соответствии с текущей локалью (поместит «ü» после «u» в немецкий язык и т. д.).

from locale import setlocale, strxfrm, LC_ALL
import operator

# call setlocale to init current locale
setlocale(LC_ALL, "")

def locale_keyfunc(keyfunc):  
  def locale_wrapper(obj):
    return strxfrm(keyfunc(obj))
  return locale_wrapper

list_of_dicts.sort(key=locale_keyfunc(operator.itemgetter("name")))

Это, конечно, использует, что сортировка локали - это «естественный» вид пользовательского интерфейса, который вы хотите эмулировать с помощью .lower ().

Я поражен тем, что модуль locale python неизвестен и не используется, он наверняка является важным компонентом в приложении, которое я пишу (переведен на несколько языков, но языковой модуль важен для того, чтобы даже получить модуль one вправо. Пример: V 'и' W ', так что вам нужно их сопоставить. locale делает все это для вас.). В локали POSIX (не по умолчанию) это вернет сортировку «a» после «Z».

4
ответ дан u0b34a0f6ae 19 August 2018 в 09:27
поделиться
  • 1
    Это хорошее предложение, просто измените keyfunc на: def keyfunc (dic): return strxfrm (dic [& quot; name & quot;]) – Francesco 8 September 2009 в 18:24
  • 2
    Франческо: Теперь он использует более настраиваемый заводский стиль (хотя он может быть специализированным, чтобы быть быстрее, это редко имеет значение). – u0b34a0f6ae 8 September 2009 в 18:30
Другие вопросы по тегам:

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