item filter dalam kamus python di mana kunci berisi string tertentu

97

Saya seorang pembuat kode C yang mengembangkan sesuatu dengan python. Saya tahu bagaimana melakukan hal berikut di C (dan karenanya dalam logika seperti C yang diterapkan pada python), tapi saya bertanya-tanya apa cara 'Python' untuk melakukannya.

Saya memiliki kamus d, dan saya ingin mengoperasikan sebagian item, hanya mereka yang kuncinya (string) berisi substring tertentu.

yaitu logika C akan menjadi:

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

Saya membayangkan versi python akan seperti itu

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

Saya telah menemukan banyak posting di sini tentang memfilter kamus, tetapi tidak dapat menemukan satu pun yang melibatkan hal ini.

Kamus saya tidak bersarang dan saya menggunakan python 2.7

memo
sumber
stackoverflow.com/questions/2844516/python-filter-a-dictionary
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

187

Bagaimana dengan pemahaman dict :

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

Begitu Anda melihatnya, seharusnya sudah cukup jelas, karena terbaca seperti bahasa Inggris dengan cukup baik.

Sintaks ini membutuhkan Python 2.7 atau lebih tinggi.

Di Python 3, hanya ada dict.items(), Anda tidak iteritems()akan menggunakan:

filtered_dict = {k:v for (k,v) in d.items() if filter_string in k}
Jonathon Reinhart
sumber
1
Mengapa tidak filtered_dict = {k:d[k] for k in d if filter_string in k}?
thefourtheye
5
@thefourtheye Saya akan menebak bahwa milik saya lebih cepat, karena tidak melakukan d[k]pencarian.
Jonathon Reinhart
Juga, katanya # do somethingdi komentar, tapi kami menjatuhkan beberapa kunci di sini.
thefourtheye
Apakah kita punya iteritemsPython 3? Saya rasa tidak. Jadi, versi saya akan kompatibel, bukan?
thefourtheye
1
Di Python 3 Anda akan mengganti iteritemsdengan items, yang sama dengan Python 2.7 iteritems.
Jonathon Reinhart
18

Pilih apa pun yang paling mudah dibaca dan dipelihara. Hanya karena Anda dapat menuliskannya dalam satu baris tidak berarti Anda harus menuliskannya. Solusi Anda yang ada dekat dengan apa yang akan saya gunakan selain saya akan menggunakan iteritems untuk melewati pencarian nilai, dan saya benci jika saya dapat menghindarinya:

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

Namun jika Anda benar-benar menginginkan sesuatu untuk membiarkan Anda mengulang melalui dikt yang difilter maka saya tidak akan melakukan proses dua langkah untuk membangun dikt yang difilter dan kemudian mengulanginya, melainkan menggunakan generator, karena apa yang lebih pythonic (dan mengagumkan) daripada generator?

Pertama, kami membuat generator, dan desain yang bagus mengharuskan kami membuatnya cukup abstrak agar dapat digunakan kembali:

# 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

Dan kemudian kita dapat menggunakan generator untuk menyelesaikan masalah Anda dengan baik dan rapi dengan kode yang sederhana dan dapat dimengerti:

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

Singkatnya: generator itu luar biasa.

Brendan F
sumber
11

Anda dapat menggunakan fungsi filter bawaan untuk memfilter kamus, daftar, dll. Berdasarkan kondisi tertentu.

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

Keuntungannya adalah Anda dapat menggunakannya untuk berbagai struktur data.

Pulkit
sumber
Perhatikan itu items:harus item:dalam definisi lambda.
suap
Terima kasih @bkribbs karena telah menunjukkan kesalahan tersebut. Saya telah memperbaikinya sekarang.
Pulkit
8
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}
jspurim.dll
sumber
3
Metode saya menggunakan iteritems()akan menjadi lebih efisien daripada items().
Jonathon Reinhart
@Jonathin Reinhart Saya tidak tahu tentang itu. Terima kasih.
jspurim
2
Hanya pada Python 2.7. Di Python 3 hanya ada items() , yang bertindak seperti Python 2.7 iteritems.
Jonathon Reinhart
1
Pertanyaannya secara eksplisit untuk python 2.7
Brendan F
7

Jonathon memberi Anda pendekatan menggunakan pemahaman dikt dalam jawabannya . Berikut adalah pendekatan yang berhubungan dengan Anda do sesuatu bagian.

Jika Anda ingin melakukan sesuatu dengan nilai-nilai kamus, Anda tidak memerlukan pemahaman kamus sama sekali:

Saya menggunakan iteritems() karena Anda menandai pertanyaan Anda dengan

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

Sekarang hasilnya akan ada dalam daftar dengan some_functionditerapkan ke setiap pasangan kunci / nilai kamus, yang ada foodi kuncinya.

Jika Anda hanya ingin menangani nilai-nilai dan mengabaikan kuncinya, cukup ubah pemahaman daftar:

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

some_function bisa dipanggil apa saja, jadi lambda juga akan berfungsi:

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

Daftar bagian dalam sebenarnya tidak diperlukan, karena Anda juga dapat meneruskan ekspresi generator ke peta:

>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]
Burhan Khalid
sumber
menarik. bagaimana some_function didefinisikan? pada kasus pertama (k, v), apakah hanya membutuhkan dua parameter? kunci pertama lalu nilai?
memo
Ya, hanya bisa dipanggil. Jadi map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))- ini akan memberimu [4].
Burhan Khalid
Ini benar, tetapi lebih pythonic daripada menggunakan mapadalah pemahaman daftar. [f(v) for k, v in d.iteritems() if substring in k]Saya pikir ini jauh lebih mudah dibaca, dan lebih efisien.
Davidmh
@memo Tidak akan mengambil dua parameter, ini akan mengambil satu parameter dengan dua elemen. Ada juga starmap yang akan membongkar menjadi dua argumen, namun ini adalah iterator yang malas (harus diulang sebelum dijalankan, yaitu results = list(starmap(...))atau for result in starmap(...): ...).
nmclean