Python - Kembalikan kunci N pertama: pasangan nilai dari dict

109

Perhatikan kamus berikut, d:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Saya ingin mengembalikan kunci N pertama: pasangan nilai dari d (N <= 4 dalam kasus ini). Metode apa yang paling efisien untuk melakukan ini?

Jason Strimpel
sumber
1
Peringatan. Tampaknya banyak informasi yang salah dalam jawaban. Pengujian saya menunjukkan tidak ada satu solusi pun yang lebih cepat dari list(d.items())[:4]. list () adalah implementasi yang mendasari banyak jawaban.
BSalita

Jawaban:

115

Tidak ada yang namanya kunci "n pertama" karena a dict tidak ingat kunci mana yang dimasukkan lebih dulu.

Anda bisa mendapatkan setiap pasangan n kunci-nilai meskipun:

n_items = take(n, d.iteritems())

Ini menggunakan implementasi takedari itertoolsresep :

from itertools import islice

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

Lihat itu bekerja secara online: ideone


Pembaruan untuk Python 3.6

n_items = take(n, d.items())
Mark Byers
sumber
42
Saya percaya iteritemsharus diganti denganitems untuk orang-orang di Python 3
Monica Heddneck
1
@MonicaHeddneck, brilian, terima kasih telah menambahkan komentar ini.
Karl Baker
12
Pemula di sini - apakah take()bagian dari basis kode python di mana saja? Atau, apakah ini murni fungsi yang Anda tentukan dalam jawaban Anda di sini? Bertanya seolah-olah itu adalah bagian dari basis kode, saya tidak dapat menemukan / mengimpornya. :)
Scott Borden
81

Cara yang sangat efisien untuk mengambil apa pun adalah dengan menggabungkan pemahaman daftar atau kamus dengan pengirisan. Jika Anda tidak perlu memesan item (Anda hanya ingin n pasang acak), Anda dapat menggunakan pemahaman kamus seperti ini:

# Python 2
first2pairs = {k: mydict[k] for k in mydict.keys()[:2]}
# Python 3
first2pairs = {k: mydict[k] for k in list(mydict)[:2]}

Umumnya pemahaman seperti ini selalu lebih cepat dijalankan daripada pengulangan "untuk x dalam y" yang setara. Selain itu, dengan menggunakan .keys () untuk membuat daftar kunci kamus dan memotong daftar itu, Anda menghindari 'menyentuh' tombol yang tidak perlu saat Anda membuat kamus baru.

Jika Anda tidak memerlukan kunci (hanya nilai), Anda dapat menggunakan pemahaman daftar:

first2vals = [v for v in mydict.values()[:2]]

Jika Anda membutuhkan nilai yang diurutkan berdasarkan kuncinya, itu tidak lebih merepotkan:

first2vals = [mydict[k] for k in sorted(mydict.keys())[:2]]

atau jika Anda juga membutuhkan kuncinya:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}
monotasker
sumber
2
Yang ini adalah solusi yang lebih baik jika Anda ingin memilih N banyak pasangan kunci: nilai sebagai kamus, bukan sebagai daftar
fermat4214
1
@ fermat4214 Apakah ini suatu masalah, jika seluruh kamus saya tercetak ketika saya menjalankan perintah ini?
Ted Taylor of Life
list (mydict) [: 2] akan sia-sia jika Anda tidak perlu mengurutkan kamus dan hanya perlu 2 elemen pertama. Bagaimana jika kamus memiliki 1 juta kv pasang? Mengonversi semuanya menjadi daftar itu mahal. Solusi Mark Byers jauh lebih baik.
JJ
Ini harus menjadi solusinya!
Guenter
14

S Python dicttidak berurut, jadi tidak ada artinya meminta kunci "N pertama".

The collections.OrderedDictkelas tersedia jika itu yang Anda butuhkan. Anda bisa secara efisien mendapatkan empat elemen pertamanya sebagai

import itertools
import collections

d = collections.OrderedDict((('foo', 'bar'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')))
x = itertools.islice(d.items(), 0, 4)

for key, value in x:
    print key, value

itertools.islicememungkinkan Anda untuk dengan malas mengambil sepotong elemen dari iterator mana pun. Jika Anda ingin hasilnya dapat digunakan kembali, Anda perlu mengubahnya menjadi daftar atau semacamnya, seperti ini:

x = list(itertools.islice(d.items(), 0, 4))
Jeremy
sumber
Tidak terlihat malas. Membutuhkan waktu 2x lebih lama dari `daftar (d.items ()) [: 4]
BSalita
12
foo = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
iterator = iter(foo.items())
for i in range(3):
    print(next(iterator))

Pada dasarnya, ubah tampilan (dict_items) menjadi iterator, lalu lakukan iterasi dengan next ().

cop4587
sumber
2
Jawaban yang fantastis, ini adalah satu-satunya jawaban di halaman ini yang berhasil untuk saya dan juga dapat dibaca. Juga, saya dapat memverifikasi ini berfungsi dengan Python 3, yang tampaknya tidak dapat dilakukan oleh beberapa jawaban lama.
cdahms
7

Tidak melihatnya di sini. Tidak akan dipesan tetapi yang paling sederhana secara sintaksis jika Anda hanya perlu mengambil beberapa elemen dari kamus.

n = 2
{key:value for key,value in d.items()[0:n]}
pengguna2623954
sumber
7
Saya mencoba kode Anda tetapi saya mendapatkan kesalahan ini: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (saham adalah nama kamus saya)
Moondra
2
@Moondra - Harus mengonversi ke dalam daftar sebelum menjalankan item kamus. Di atas kode, baris berfungsi jika {key: value for key, value in list (d.items ()) [0: n]}
Rajesh Mappu
{A: N untuk (A, N) di [x untuk x di d.items ()] [: 4]}
farid khafizov
6

Untuk mendapatkan elemen N teratas dari kamus python Anda, seseorang dapat menggunakan baris kode berikut:

list(dictionaryName.items())[:N]

Dalam kasus Anda, Anda dapat mengubahnya menjadi:

list(d.items())[:4]
thevatsalsaglani.dll
sumber
3

Lihat PEP 0265 tentang pengurutan kamus. Kemudian gunakan kode iterable yang disebutkan di atas.

Jika Anda membutuhkan efisiensi lebih dalam pasangan kunci-nilai yang diurutkan. Gunakan struktur data yang berbeda. Yaitu, yang mempertahankan urutan terurut dan pengaitan nilai kunci.

Misalnya

import bisect

kvlist = [('a', 1), ('b', 2), ('c', 3), ('e', 5)]
bisect.insort_left(kvlist, ('d', 4))

print kvlist # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
silverjam.dll
sumber
3

di py3, ini akan berhasil

{A:N for (A,N) in [x for x in d.items()][:4]}

{'a': 3, 'b': 2, 'c': 3, 'd': 4}

farid khafizov
sumber
2

tambahkan saja jawaban menggunakan zip,

{k: d[k] for k, _ in zip(d, range(n))}
Peter Li
sumber
1

Ini tergantung pada apa yang 'paling efisien' dalam kasus Anda.

Jika Anda hanya ingin sampel semi-acak dari kamus besar foo, menggunakan foo.iteritems()dan mengambil nilai sebanyak yang Anda butuhkan, ini adalah operasi malas yang menghindari pembuatan daftar eksplisit kunci atau item.

Jika Anda perlu mengurutkan kunci terlebih dahulu, tidak ada cara lain untuk menggunakan sesuatu seperti keys = foo.keys(); keys.sort()atau sorted(foo.iterkeys()), Anda harus membuat daftar kunci yang eksplisit. Kemudian iris atau ulangi melalui N pertama keys.

BTW mengapa Anda peduli dengan cara 'efisien'? Apakah Anda membuat profil program Anda? Jika tidak, gunakan cara yang jelas dan mudah dipahami terlebih dahulu. Kemungkinannya akan berhasil dengan baik tanpa menjadi hambatan.

9000
sumber
Ini adalah aplikasi untuk program keuangan dan saya berusaha membuat setiap baris kode seefisien mungkin. Saya tidak membuat profil program dan setuju bahwa ini mungkin bukan masalah besar tetapi saya ingin meminta solusi yang efisien secara default. Terima kasih balasannya.
Jason Strimpel
0

Anda dapat melakukan pendekatan ini dengan berbagai cara. Jika pesanan penting, Anda dapat melakukan ini:

for key in sorted(d.keys()):
  item = d.pop(key)

Jika pesanan bukan masalah, Anda dapat melakukan ini:

for i in range(4):
  item = d.popitem()
gddc
sumber
Dalam cuplikan pertama Anda mungkin harus menyebutnya valuebukan itemuntuk kejelasan.
agf
0

Dictionary tidak memiliki urutan, jadi sebelum memilih pasangan nilai kunci N teratas, mari kita lakukan pengurutan.

import operator
d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
#itemgetter(0)=sort by keys, itemgetter(1)=sort by values

Sekarang kita dapat melakukan pengambilan elemen 'N' teratas :, menggunakan struktur metode seperti ini:

def return_top(elements,dictionary_element):
    '''Takes the dictionary and the 'N' elements needed in return
    '''
    topers={}
    for h,i in enumerate(dictionary_element):
        if h<elements:
            topers.update({i:dictionary_element[i]})
    return topers

untuk mendapatkan 2 elemen teratas, cukup gunakan struktur ini:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
d=return_top(2,d)
print(d)
Jyothish Arumugam
sumber
0

Untuk Python 3 ke atas, Untuk memilih n Pasangan pertama

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}
Shivpe_R
sumber
0

pertimbangkan sebuah dikt

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

from itertools import islice
n = 3
list(islice(d.items(),n))

islice akan melakukan triknya :) semoga bisa membantu!

Vivek Ananthan
sumber
0

Ini mungkin tidak terlalu elegan, tetapi berhasil untuk saya:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

x= 0
for key, val in d.items():
    if x == 2:
        break
    else:
        x += 1
        # Do something with the first two key-value pairs
Thorsten Stehlik
sumber
0

Saya telah mencoba beberapa jawaban di atas dan mencatat bahwa beberapa di antaranya bergantung pada versi dan tidak berfungsi di versi 3.7.

Saya juga mencatat bahwa sejak 3.6 semua kamus diurutkan berdasarkan urutan penyisipan item.

Meskipun kamus diurutkan sejak 3.6, beberapa pernyataan yang Anda harapkan bisa bekerja dengan struktur yang teratur sepertinya tidak berfungsi.

Jawaban atas pertanyaan OP yang paling cocok untuk saya.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]
Mark Kortink
sumber
FYI, 5x lebih lambat darilst = list(d.items())[:N]
BSalita
0
def GetNFirstItems(self):
    self.dict = {f'Item{i + 1}': round(uniform(20.40, 50.50), 2) for i in range(10)}#Example Dict
    self.get_items = int(input())
    for self.index,self.item in zip(range(len(self.dict)),self.dict.items()):
        if self.index==self.get_items:
          break
        else:
            print(self.item,",",end="")

Pendekatan yang tidak biasa, karena memberikan kompleksitas waktu O (N) yang intens.

Shashwata Shastri
sumber