python:组合sort-key-functions itemgetter和str.lower

时间:2009-09-08 14:56:25

标签: python function sorting key

我想按字典键对字典列表进行排序,我不想区分大写和小写字符。

dict1 = {'name':'peter','phone':'12355'}
dict2 = {'name':'Paul','phone':'545435'}
dict3 = {'name':'klaus','phone':'55345'}
dict4 = {'name':'Krishna','phone':'12345'}
dict5 = {'name':'Ali','phone':'53453'}
dict6 = {'name':'Hans','phone':'765756'}
list_of_dicts = [dict1,dict2,dict3,dict4,dict5,dict6]

key_field = 'name'
list_of_dicts.sort(key=itemgetter(key_field))
# how to combine key=itemgetter(key_field) and key=str.lower? 
for list_field in list_of_dicts:
    print list_field[key_field]

应提供

Ali, Hans, klaus, Krishna, Paul, peter

而不是

klaus, peter, Ali, Hans, Krishna, Paul

7 个答案:

答案 0 :(得分:14)

这个怎么样:

list_of_dicts.sort(key=lambda a: a['name'].lower())

答案 1 :(得分:10)

在一般情况下,您需要编写密钥提取功能以进行排序;只有在特殊的(虽然很重要的)情况下,您可以重复使用现有的可调用来为您提取密钥,或者只是将几个现有的密码连接起来(使用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'))适用于您的情况。

请注意,虽然过度泛化具有成本,有品味和适度的泛化(留下项密钥,方法名称和方法参数,如果有的话,在这种情况下由运行时确定)通常会带来好处 - 一个通用功能,而不是更多复杂的十几个特定的​​和专门的(使用提取器,调用方法或两者,在他们的代码中硬连线),将更容易维护(当然,更容易重用! - )。

答案 2 :(得分:4)

为了便于阅读,你可能应该使用lambda。但是作为对高阶函数的有趣研究,这里是Python中q-combinator的扩展版本(也称为奇怪的鸟类组合子)。这允许您通过组合两个函数来创建新函数

 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管道相似。

答案 3 :(得分:4)

此解决方案将使用您的系统区域设置,作为奖励,它将根据当前区域设置对最终的其他字符进行排序(将“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()模拟的用户界面“自然”排序。

我很惊讶python的locale模块是未知且未使用的,它肯定是我编写的应用程序中的一个重要组件(翻译成多种语言,但语言环境模块对于获取非常重要一个模块正确。例如:瑞典语'V'和'W'类似,所以你必须整理它们。locale为你完成所有这些。)。 在POSIX区域设置(非默认)中,这将在“Z”之后恢复为“a”排序。

答案 4 :(得分:4)

就个人而言,我希望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)

答案 5 :(得分:4)

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

答案 6 :(得分:2)

def lower_getter(field):
    def _getter(obj):
        return obj[field].lower()
    return _getter

list_of_dicts.sort(key=lower_getter(key_field))