Python - вернуть первый ключ N: пары значений из dict

109

Рассмотрим следующий словарь, d:

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

Я хочу вернуть первые N пар ключ: значение из d (в данном случае N <= 4). Какой метод для этого наиболее эффективен?

Джейсон Стримпель
источник
1
Осторожно. Кажется, в ответах много дезинформации. Мои тесты показывают, что ни одно решение не быстрее, чем list(d.items())[:4]. list () является базовой реализацией для многих ответов.
BSalita

Ответы:

115

Не существует такой вещи, как "первые n" ключей, потому что a dictне помнит, какие ключи были вставлены первыми.

Однако вы можете получить любые n пар ключ-значение:

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

Здесь используется реализация takeиз itertoolsрецептов :

from itertools import islice

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

Посмотрите, как это работает в Интернете: ideone


Обновление для Python 3.6

n_items = take(n, d.items())
Марк Байерс
источник
42
Я считаю, что iteritemsследует заменить на itemsдля людей на Python 3
Моника Хедднек
1
@MonicaHeddneck, молодец, спасибо, что добавили этот комментарий.
Карл Бейкер
12
Здесь новичок - есть take()ли где-нибудь часть базы кода Python? Или это просто функция, которую вы определили здесь в своем ответе? Спрашивая, как будто это часть базы кода, я не могу его найти / импортировать. :)
Скотт Борден
81

Очень эффективный способ получить что-либо - объединить понимание списка или словаря с нарезкой. Если вам не нужно заказывать элементы (вам просто нужно n случайных пар), вы можете использовать понимание словаря следующим образом:

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

Обычно подобное понимание всегда выполняется быстрее, чем эквивалентный цикл «for x in y». Кроме того, используя .keys () для создания списка ключей словаря и нарезки этого списка, вы избегаете «касания» любых ненужных ключей при создании нового словаря.

Если вам не нужны ключи (только значения), вы можете использовать понимание списка:

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

Если вам нужны значения, отсортированные по их ключам, это не проблема:

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

или, если вам нужны ключи:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}
монотонный
источник
2
Это лучшее решение, если вы хотите выбрать N много пар ключ: значение как словарь, а не как список
fermat4214
1
@ fermat4214 Это проблема, если весь мой словарь распечатывается, когда я запускаю любую из этих команд?
Тед Тейлор из Life
list (mydict) [: 2] бесполезен, если вам не нужно сортировать словарь и нужны только первые 2 элемента. Что делать, если в словаре есть 1 млн кв пар? Преобразование всего этого в список стоит дорого. Решение Марка Байерса намного лучше.
JJ
Это должно быть решением!
Гюнтер
14

dictS Python не упорядочены, поэтому бессмысленно запрашивать «первые N» ключей.

collections.OrderedDictКласс доступен , если это то, что вам нужно. Вы можете эффективно получить его первые четыре элемента как

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.isliceпозволяет вам лениво брать срез элементов из любого итератора. Если вы хотите, чтобы результат можно было использовать повторно, вам нужно преобразовать его в список или что-то в этом роде, например:

x = list(itertools.islice(d.items(), 0, 4))
Джереми
источник
Не выгляжу ленивым. Занимает в 2 раза больше времени, чем `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))

По сути, превратите представление (dict_items) в итератор, а затем повторите его с помощью next ().

коп4587
источник
2
Фантастический ответ, это единственный ответ на этой странице, который сработал для меня и также удобочитаем. Кроме того, я могу проверить, что это работает с Python 3, чего не делают некоторые из старых ответов.
cdahms
7

Не видел его здесь. Не будет упорядочен, но синтаксически простейший, если вам нужно просто взять какие-то элементы из словаря.

n = 2
{key:value for key,value in d.items()[0:n]}
user2623954
источник
7
Я пробовал код, но получаю эту ошибку: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (акции - это название моего словаря)
Moondra
2
@Moondra - необходимо преобразовать в список перед просмотром элементов словаря. Выше кода строка работает, если {ключ: значение для ключа, значение в списке (d.items ()) [0: n]}
Раджеш Маппу,
{A: N вместо (A, N) в [x вместо x в d.items ()] [: 4]}
фарид хафизов 02
6

Чтобы получить верхние N элементов из вашего словаря Python, можно использовать следующую строку кода:

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

В вашем случае вы можете изменить его на:

list(d.items())[:4]
Thevatsalsaglani
источник
3

См. PEP 0265 о сортировке словарей. Затем используйте вышеупомянутый повторяющийся код.

Если вам нужно больше эффективности в отсортированных парах "ключ-значение". Используйте другую структуру данных. То есть тот, который поддерживает отсортированный порядок и ассоциации "ключ-значение".

Например

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
источник
3

в py3 это поможет

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

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

фарид хафизов
источник
2

просто добавьте ответ, используя zip,

{k: d[k] for k, _ in zip(d, range(n))}
Питер Ли
источник
1

Это зависит от того, что «наиболее эффективно» в вашем случае.

Если вам просто нужна полуслучайная выборка из огромного словаря foo, используйте foo.iteritems()и берите из нее столько значений, сколько вам нужно, это ленивая операция, которая позволяет избежать создания явного списка ключей или элементов.

Если вам нужно сначала отсортировать ключи, нет способа использовать что-то вроде keys = foo.keys(); keys.sort()или sorted(foo.iterkeys()), вам придется создать явный список ключей. Затем нарезать или итерация через первую N keys.

Кстати, почему вас волнует «эффективный» способ? Вы профилировали свою программу? Если вы этого не сделали, используйте сначала очевидный и простой для понимания способ. Скорее всего, он будет работать хорошо, но не станет узким местом.

9000
источник
Это было приложение к финансовой программе, и я стараюсь построить каждую строчку кода как можно эффективнее. Я не профилировал программу и согласен, что это, вероятно, не будет узким местом, но я хотел бы просить эффективных решений по умолчанию. Спасибо за ответ.
Джейсон Стримпел 03
0

Вы можете подойти к этому несколькими способами. Если порядок важен, вы можете сделать это:

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

Если порядок не является проблемой, вы можете сделать это:

for i in range(4):
  item = d.popitem()
gddc
источник
В первом фрагменте вам, вероятно, следует назвать его, valueа не itemдля ясности.
agf 01
0

Словарь не поддерживает порядок, поэтому, прежде чем выбирать верхние N пар ключ-значение, давайте отсортируем его.

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

Теперь мы можем извлечь верхние N элементов :, используя такую ​​структуру метода:

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

чтобы получить 2 верхних элемента, просто используйте эту структуру:

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

Для Python 3 и выше, чтобы выбрать первые n пар

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}
Шивпе_Р
источник
0

считать диктат

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

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

islice сделает свое дело :) надеюсь, что это поможет!

Вивек Анантан
источник
0

Это может быть не очень элегантно, но у меня работает:

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

Я попробовал несколько ответов выше и заметил, что некоторые из них зависят от версии и не работают в версии 3.7.

Также отмечу, что начиная с версии 3.6 все словари упорядочены по последовательности вставки элементов.

Несмотря на то, что словари упорядочены, начиная с версии 3.6, некоторые из операторов, которые вы ожидаете работать с упорядоченными структурами, похоже, не работают.

Ответ на вопрос OP, который лучше всего сработал для меня.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]
Марк Кортинк
источник
К вашему сведению, в 5 раз медленнее, чем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="")

Необычный подход, так как он выдает интенсивную временную сложность O (N).

Шашвата Шастри
источник