lọc các mục trong từ điển python nơi các khóa chứa một chuỗi cụ thể


95

Tôi là một lập trình viên C đang phát triển một thứ gì đó trong python. Tôi biết cách thực hiện những điều sau trong C (và do đó trong logic giống C được áp dụng cho python), nhưng tôi đang tự hỏi cách làm của 'Python' là gì.

Tôi có một từ điển d và tôi muốn thao tác trên một tập hợp con của các mục, chỉ những người có khóa (chuỗi) mới chứa một chuỗi con cụ thể.

tức là logic C sẽ là:

for key in d:
    if filter_string in key:
        # do something
    else
        # do nothing, continue

Tôi đang tưởng tượng phiên bản python sẽ giống như

filtered_dict = crazy_python_syntax(d, substring)
for key,value in filtered_dict.iteritems():
    # do something

Tôi đã tìm thấy rất nhiều bài đăng trên đây liên quan đến việc lọc từ điển, nhưng không thể tìm thấy bài nào liên quan đến chính xác vấn đề này.

Từ điển của tôi không được lồng vào nhau và tôi đang sử dụng python 2.7



Câu trả lời:


182

Làm thế nào về việc hiểu chính tả :

filtered_dict = {k:v for k,v in d.iteritems() if filter_string in k}

Một trong những bạn thấy nó, nó nên được tự giải thích, vì nó đọc giống như tiếng Anh khá tốt.

Cú pháp này yêu cầu Python 2.7 trở lên.

Trong Python 3, chỉ có dict.items(), không phải iteritems()vì vậy bạn sẽ sử dụng:

filtered_dict = {k:v for (k,v) in d.items() if filter_string in k}

1
Tại sao không filtered_dict = {k:d[k] for k in d if filter_string in k}?
thefourtheye

5
@thefourtheye Tôi sẽ đoán rằng của tôi nhanh hơn, vì nó không diễn ra quá trình d[k]tra cứu.
Jonathon Reinhart

Ngoài ra, anh ấy nói # do somethingtrong các bình luận, nhưng chúng tôi bỏ một vài chìa khóa ở đây.
thefourtheye

Chúng ta có iteritemstrong Python 3 không? Tôi không nghĩ vậy. Vì vậy, phiên bản của tôi sẽ tương thích, không?
thefourtheye

1
Trong Python 3, bạn sẽ thay thế iteritemsbằng items, tương tự như Python 2.7 iteritems.
Jonathon Reinhart

17

Chọn bất cứ thứ gì dễ đọc và dễ bảo trì nhất. Chỉ vì bạn có thể viết nó ra trong một dòng không có nghĩa là bạn nên làm như vậy. Giải pháp hiện tại của bạn gần với những gì tôi sẽ sử dụng khác với những gì tôi sẽ sử dụng lặp lại để bỏ qua tra cứu giá trị và tôi ghét các ifs lồng nhau nếu tôi có thể tránh chúng:

for key, val in d.iteritems():
    if filter_string not in key:
        continue
    # do something

Tuy nhiên, nếu bạn thực sự muốn một cái gì đó cho phép bạn lặp lại qua một mệnh lệnh đã lọc thì tôi sẽ không thực hiện quy trình hai bước là xây dựng chính lệnh đã lọc và sau đó lặp lại nó, mà thay vào đó sử dụng trình tạo, bởi vì điều gì thú vị hơn (và tuyệt vời) hơn một máy phát điện?

Đầu tiên, chúng tôi tạo trình tạo của chúng tôi và thiết kế tốt yêu cầu chúng tôi làm cho nó đủ trừu tượng để có thể tái sử dụng:

# The implementation of my generator may look vaguely familiar, no?
def filter_dict(d, filter_string):
    for key, val in d.iteritems():
        if filter_string not in key:
            continue
        yield key, val

Và sau đó, chúng tôi có thể sử dụng trình tạo để giải quyết vấn đề của bạn một cách tốt đẹp và rõ ràng với mã đơn giản, dễ hiểu:

for key, val in filter_dict(d, some_string):
    # do something

Tóm lại: máy phát điện thật tuyệt vời.


11

Bạn có thể sử dụng chức năng lọc tích hợp để lọc từ điển, danh sách, v.v. dựa trên các điều kiện cụ thể.

filtered_dict = dict(filter(lambda item: filter_str in item[0], d.items()))

Ưu điểm là bạn có thể sử dụng nó cho các cấu trúc dữ liệu khác nhau.


Lưu ý rằng items:phải có item:trong định nghĩa lambda.
bkribbs

Cảm ơn bạn @bkribbs đã chỉ ra lỗi. Tôi đã sửa chữa nó ngay bây giờ.
Pulkit

8
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}

3
Phương pháp của tôi iteritems()đang sử dụng sẽ hiệu quả hơn items().
Jonathon Reinhart

@Jonathin Reinhart Tôi không biết về nó. Cảm ơn.
jspurim

2
Chỉ trên Python 2.7. Trong Python 3, chỉ có items() , hoạt động giống như Python 2.7 iteritems.
Jonathon Reinhart

1
Câu hỏi rõ ràng dành cho python 2.7
Brendan F

7

Jonathon đã cho bạn một cách tiếp cận bằng cách sử dụng khả năng hiểu chính tả trong câu trả lời của mình . Đây là một phương pháp giao dịch với bạn làm điều gì đó một phần.

Nếu bạn muốn làm điều gì đó với các giá trị của từ điển, bạn không cần phải hiểu từ điển chút nào:

Tôi đang sử dụng iteritems() vì bạn đã gắn thẻ câu hỏi của mình với

results = map(some_function, [(k,v) for k,v in a_dict.iteritems() if 'foo' in k])

Bây giờ kết quả sẽ nằm trong danh sách some_functionđược áp dụng cho từng cặp khóa / giá trị của từ điển, có footrong khóa của nó.

Nếu bạn chỉ muốn xử lý các giá trị và bỏ qua các khóa, chỉ cần thay đổi cách hiểu danh sách:

results = map(some_function, [v for k,v in a_dict.iteritems() if 'foo' in k])

some_function có thể được gọi bất kỳ, vì vậy lambda cũng sẽ hoạt động:

results = map(lambda x: x*2, [v for k,v in a_dict.iteritems() if 'foo' in k])

Danh sách bên trong thực sự không bắt buộc, vì bạn cũng có thể chuyển một biểu thức trình tạo để ánh xạ:

>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]

hấp dẫn. some_ function sẽ được định nghĩa như thế nào? trong trường hợp đầu tiên (k, v), nó chỉ nhận hai tham số? khóa đầu tiên sau đó giá trị?
bản ghi nhớ

Vâng, chỉ là một cuộc gọi. Vì vậy map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))- điều này sẽ cung cấp cho bạn [4].
Burhan Khalid

Điều này đúng, nhưng điều khó hiểu hơn là sử dụng maplà sự hiểu danh sách. [f(v) for k, v in d.iteritems() if substring in k]Tôi nghĩ nó dễ đọc hơn và hiệu quả hơn.
Davidmh

@memo Nó không cần hai tham số, nó sẽ lấy một tham số duy nhất với hai phần tử. Ngoài ra còn có starmap sẽ giải nén thành hai đối số, tuy nhiên nó là một trình lặp lười biếng (phải được lặp lại trước khi nó thực thi, tức là results = list(starmap(...))hoặc for result in starmap(...): ...).
nmclean
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.