[英]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.