2009-09-08 21 views
6

Tôi muốn sắp xếp danh sách các từ điển theo từ điển, ở đây tôi không muốn phân biệt giữa chữ hoa và chữ thường.python: kết hợp các loại khóa-chức năng itemgetter và 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] 

nên cung cấp

Ali, Hans, klaus, Krishna, Paul, peter 

và không

klaus, peter, Ali, Hans, Krishna, Paul 

Trả lời

10

Trong trường hợp chung, bạn sẽ muốn viết chức năng trích xuất khóa của bạn cho các mục đích phân loại; chỉ trong trường hợp đặc biệt (mặc dù quan trọng) nó xảy ra mà bạn có thể tái sử dụng một cuộc gọi hiện có để trích xuất các phím cho bạn, hoặc chỉ cần kết hợp một vài cái hiện có (theo cách "nhanh chóng và bẩn" bằng cách sử dụng lambda, vì không có theo cách để làm thành phần chức năng).

Nếu bạn thường xuyên cần phải thực hiện hai loại hoạt động cho khai thác chính (có được một mục và gọi một phương thức trên mục đó), tôi đề nghị:

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

nên listofdicts.sort(key=combiner('name', 'lower')) sẽ làm việc trong trường hợp của bạn. Lưu ý rằng trong khi khái quát hóa quá mức có chi phí, tổng quát trang nhã và vừa phải (để lại khóa mục, tên phương thức và đối số phương thức nếu có, như thời gian chạy được xác định, trong trường hợp này) thường có lợi ích - một hàm tổng quát, chứ không phải là một hàm tổng quát, chứ không phải phức tạp hơn chục cái cụ thể và chuyên biệt (với bộ giải nén, phương thức gọi, hoặc cả hai, được mã hóa trong mã của chúng), sẽ dễ bảo trì hơn (và, tất nhiên, dễ sử dụng hơn nhiều -).

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

list_of_dicts.sort(key=lower_getter(key_field)) 
+0

và như là một cộng, nó sẽ tự động làm việc với cả bytestrings và chuỗi unicode. – nosklo

12

Làm thế nào về điều này:

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

tôi nhận được một thông báo lỗi "Không iteratable" – chovy

4

Bạn có lẽ nên đi với một lambda vì lợi ích của dễ đọc. Nhưng như một nghiên cứu thú vị về các hàm bậc cao hơn, đây là phiên bản mở rộng của bộ phối hợp q trong Python (còn được gọi là tổ hợp chim kỳ quặc). Điều này cho phép bạn tạo ra một chức năng mới bằng cách soạn hai chức năng

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

Nếu bạn đảo ngược các định nghĩa của bên trong và bên ngoài trong compose chức năng, bạn sẽ có được b-combinator truyền thống hơn (bluebird). Tôi thích bộ phối hợp nhiều hơn vì sự tương tự với các đường ống unix.

4

Giải pháp này sẽ sử dụng ngôn ngữ hệ thống của bạn và tiền thưởng sẽ sắp xếp các ký tự khác theo ngôn ngữ hiện tại (Sẽ đặt "ü" sau "u" bằng ngôn ngữ Đức vv).

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

Điều này tất nhiên sử dụng loại địa phương là loại giao diện người dùng "tự nhiên" mà bạn muốn mô phỏng bằng .lower().

Tôi ngạc nhiên rằng mô-đun python của locale là không rõ và không sử dụng, nó chắc chắn là một thành phần quan trọng trong việc áp dụng tôi viết (dịch sang nhiều ngôn ngữ, nhưng các module locale là quan trọng đối với thậm chí nhận được một mô-đun đúng. Trường hợp tại điểm: trong tiếng Thụy Điển 'V' và 'W' giống nhau, vì vậy bạn phải đối chiếu chúng. locale thực hiện tất cả những điều đó cho bạn.). Trong ngôn ngữ POSIX (không mặc định), điều này sẽ hoàn nguyên về sắp xếp "a" sau "Z".

+0

Đây là một gợi ý tốt đẹp, chỉ cần thay đổi keyfunc tới: def keyfunc (DIC): trở strxfrm (dic [ "name"]) – Francesco

+0

Francesco: Bây giờ nó sử dụng một nhà máy tùy biến hơn phong cách (mặc dù nó có thể được chuyên môn để được nhanh hơn, nó hiếm khi quan trọng). – u0b34a0f6ae

4

Cá nhân, tôi muốn có hai chức năng trong thư viện chuẩn của Python (có thể là trong 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 

tôi đã thực hiện những để sử dụng riêng của tôi trong jaraco.util.functools.

Dù bằng cách nào, bây giờ mã của bạn khá rõ ràng, tự ghi lại và mạnh mẽ (IMO).

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

list_of_dicts.sort(key=lowered_name) 
3
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)) 
Các vấn đề liên quan