Python - Zwróć pierwsze N ​​par klucz: wartość z dict


109

Rozważmy następujący słownik, d:

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

Chcę zwrócić pierwszy N par klucz: wartość z d (w tym przypadku N <= 4). Jaka jest najskuteczniejsza metoda zrobienia tego?


1
Uwaga. Wydaje się, że w odpowiedziach jest dużo błędnych informacji. Moje testy pokazują, że żadne rozwiązanie nie jest szybsze niż list(d.items())[:4]. list () jest podstawową implementacją wielu odpowiedzi.
BSalita

Odpowiedzi:


115

Nie ma czegoś takiego jak „pierwsze n” kluczy, ponieważ a dictnie pamięta, które klucze zostały wstawione jako pierwsze.

Możesz jednak uzyskać dowolne n par klucz-wartość:

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

Wykorzystuje to wykonanie takez itertoolsreceptur :

from itertools import islice

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

Zobacz, jak działa online: ideone


Aktualizacja dla Pythona 3.6

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

42
Uważam, że iteritemspowinien zostać zastąpiony przez itemsdla ludzi w Pythonie 3
Monica Heddneck

1
@MonicaHeddneck, genialnie, dziękuję za dodanie tego komentarza.
Karl Baker,

12
Początkujący tutaj - czy jest take()gdzieś częścią kodu Pythona? A może jest to wyłącznie funkcja, którą zdefiniowałeś w swojej odpowiedzi? Pytając, jakby to była część bazy kodu, nie mogę go znaleźć / zaimportować. :)
Scott Borden

81

Bardzo skutecznym sposobem na pobranie czegokolwiek jest połączenie wyrażeń listowych lub słownikowych z wycinaniem. Jeśli nie musisz zamawiać elementów (potrzebujesz tylko n losowych par), możesz użyć wyrażenia słownikowego w następujący sposób:

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

Ogólnie rzecz biorąc, takie rozumienie jest zawsze szybsze do wykonania niż jego odpowiednik w pętli „for x in y”. Ponadto, używając .keys () do tworzenia listy kluczy słownika i dzielenia tej listy, unikasz „dotykania” niepotrzebnych klawiszy podczas tworzenia nowego słownika.

Jeśli nie potrzebujesz kluczy (tylko wartości), możesz użyć rozumienia listowego:

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

Jeśli potrzebujesz wartości posortowanych na podstawie ich kluczy, nie stanowi to większego problemu:

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

lub jeśli potrzebujesz również kluczy:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}

2
Ten jest lepszym rozwiązaniem, jeśli chcesz wybrać N wielu par klucz: wartość jako słownik, a nie jako listę
fermat4214

1
@ fermat4214 Czy to problem, jeśli cały mój słownik zostanie wydrukowany po uruchomieniu któregokolwiek z tych poleceń?
Ted Taylor of Life

list (mydict) [: 2] jest marnotrawstwem, jeśli nie musisz sortować słownika i potrzebujesz tylko pierwszych 2 elementów. A jeśli słownik ma pary 1 mil kv? Konwersja całości na listę jest kosztowna. Rozwiązanie Marka Byersa jest znacznie lepsze.
JJ

To powinno być rozwiązanie!
Guenter

14

Pythona dictnie są uporządkowane, więc nie ma sensu prosić o „pierwsze N” kluczy.

collections.OrderedDictKlasa jest dostępna, jeśli to jest to, czego potrzebujesz. Możesz skutecznie uzyskać jego pierwsze cztery elementy jako

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.islicepozwala leniwie pobrać wycinek elementów z dowolnego iteratora. Jeśli chcesz, aby wynik był wielokrotnego użytku, musisz przekonwertować go na listę lub coś podobnego, na przykład:

x = list(itertools.islice(d.items(), 0, 4))

Nie wyglądam na leniwego. Trwa 2x dłużej niż `list (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))

Zasadniczo zamień widok (dict_items) na iterator, a następnie wykonaj iterację za pomocą next ().


2
Fantastyczna odpowiedź, to jedyna odpowiedź na tej stronie, która zadziałała dla mnie i jest również czytelna. Mogę również sprawdzić, czy to działa z Pythonem 3, czego nie wydają się niektóre starsze odpowiedzi.
cdahms

7

Nie widziałem tego tutaj. Nie będzie uporządkowana, ale najprostsza składniowo, jeśli potrzebujesz po prostu pobrać niektóre elementy ze słownika.

n = 2
{key:value for key,value in d.items()[0:n]}

7
Próbowałem kodować, ale TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} pojawia się ten błąd: (akcje to nazwa mojego słownika)
Moondra

2
@Moondra - Muszę przekonwertować na listę przed przejrzeniem elementów słownika. Powyżej kodu linia działa, jeśli {klucz: wartość klucza, wartość na liście (d.items ()) [0: n]}
Rajesh Mappu

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

6

Aby pobrać N pierwszych elementów ze słownika Pythona, można użyć następującego wiersza kodu:

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

W Twoim przypadku możesz to zmienić na:

list(d.items())[:4]

3

Zobacz PEP 0265 na temat sortowania słowników. Następnie użyj wyżej wymienionego kodu iterowalnego.

Jeśli potrzebujesz większej wydajności w posortowanych parach klucz-wartość. Użyj innej struktury danych. To znaczy taki, który utrzymuje posortowany porządek i skojarzenia klucz-wartość.

Na przykład

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

3

w py3, to załatwi sprawę

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

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


2

po prostu dodaj odpowiedź za pomocą zip,

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

1

Zależy to od tego, co jest „najbardziej wydajne” w Twoim przypadku.

Jeśli potrzebujesz tylko pół-losowej próbki dużego słownika foo, użyj foo.iteritems()i pobierz z niego tyle wartości, ile potrzebujesz, jest to leniwa operacja, która pozwala uniknąć tworzenia jawnej listy kluczy lub elementów.

Jeśli musisz najpierw posortować klucze, nie ma sposobu, aby użyć czegoś takiego jak keys = foo.keys(); keys.sort()lub sorted(foo.iterkeys()), będziesz musiał utworzyć jawną listę kluczy. Następnie kawałek lub iteracji pierwszego N keys.

A tak przy okazji, dlaczego zależy ci na „efektywnym” sposobie? Czy profilowałeś swój program? Jeśli tego nie zrobiłeś, najpierw skorzystaj z oczywistego i łatwego do zrozumienia sposobu. Są szanse, że poradzi sobie całkiem nieźle, nie stając się wąskim gardłem.


To była aplikacja do programu finansowego i staram się zbudować każdą linię kodu tak wydajnie, jak to tylko możliwe. Nie sprofilowałem programu i zgadzam się, że prawdopodobnie nie będzie to szyjka butelki, ale domyślnie lubię prosić o wydajne rozwiązania. Dziękuję za odpowiedź.
Jason Strimpel

0

Możesz podejść do tego na wiele sposobów. Jeśli zamówienie jest ważne, możesz to zrobić:

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

Jeśli zamówienie nie jest problemem, możesz to zrobić:

for i in range(4):
  item = d.popitem()

W pierwszym fragmencie prawdopodobnie powinieneś to valueraczej nazwać niż itemdla jasności.
agf

0

Słownik nie zachowuje porządku, więc przed wybraniem pierwszych N par klucz-wartość posortujmy je.

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

Teraz możemy pobrać górne „N” elementów:, używając struktury metody takiej jak:

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

aby uzyskać 2 górne elementy, po prostu użyj tej struktury:

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)

0

Dla Pythona 3 i nowszych, aby wybrać pierwsze n par

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

0

rozważ dyktando

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

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

islice załatwi sprawę :) mam nadzieję, że to pomoże!


0

To może nie być zbyt eleganckie, ale działa dla mnie:

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

0

Wypróbowałem kilka powyższych odpowiedzi i zauważyłem, że niektóre z nich są zależne od wersji i nie działają w wersji 3.7.

Zwracam również uwagę, że od 3.6 wszystkie słowniki są uporządkowane według kolejności wstawiania pozycji.

Mimo że słowniki są zamawiane od 3.6, niektóre stwierdzenia, których oczekujesz od pracy z uporządkowanymi strukturami, wydają się nie działać.

Odpowiedź na pytanie OP, która była dla mnie najlepsza.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]

Do Twojej wiadomości, 5x wolniej niżlst = 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="")

Niezwykłe podejście, ponieważ zapewnia intensywną złożoność czasu O (N).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.