簡體   English   中英

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

[英]python: combine sort-key-functions itemgetter and str.lower

我想按字典鍵對字典列表進行排序,而我不想在其中區分大小寫字符。

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

這個怎么樣:

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

在一般情況下,您將需要編寫鍵提取函數以進行排序。 僅在特殊(盡管很重要)的情況下,您可能會重復使用現有的可調用項來為您提取密鑰,或者只是將幾個現有的可調用項結合在一起(使用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'))將在您的情況下工作。

請注意,雖然過度泛化會帶來成本,但適度而適度的泛化(在這種情況下,由運行時確定,保留項目鍵,方法名稱和方法參數,如果有的話)通常會帶來好處-一個泛型函數,不會比十二個特定的和專用的代碼(在其代碼中帶有提取器,調用方法,或兩者​​都硬連接),將更易於維護(當然,也更易於重用!-)。

為了便於閱讀,您可能應該使用lambda。 但是,作為對高階函數的有趣研究,以下是Python中q-combinator的擴展版本(也稱為queer bird組合器)。 這使您可以通過組合兩個函數來創建新函數

 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函數中反轉inner和compose定義,則會得到更傳統的b組合器(bluebird)。 我更喜歡q組合器,因為它與unix管道相似。

此解決方案將使用您的系統語言環境,並且作為獎勵,它還將根據當前語言環境對其他字符進行排序(在德語語言環境中,將“ü”放在“ 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”進行排序。

我個人希望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)
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))
def lower_getter(field):
    def _getter(obj):
        return obj[field].lower()
    return _getter

list_of_dicts.sort(key=lower_getter(key_field))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM