Python - ส่งคืนคีย์ N แรก: คู่ค่าจาก dict


110

พิจารณาพจนานุกรมต่อไปนี้ d:

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

ฉันต้องการส่งคืนคู่คีย์ N แรก: ค่าจาก d (N <= 4 ในกรณีนี้) วิธีใดที่มีประสิทธิภาพที่สุดในการทำเช่นนี้?


2
ข้อควรระวัง. ดูเหมือนจะเป็นข้อมูลที่ผิดมากมายในคำตอบ 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
Monica Heddneck

1
@MonicaHeddneck ยอดเยี่ยมขอบคุณสำหรับการเพิ่มความคิดเห็นนี้
Karl Baker

13
เริ่มต้นที่นี่ - เป็นtake()ส่วนหนึ่งของฐานรหัสหลามทุกที่หรือไม่? หรือเป็นฟังก์ชันที่คุณกำหนดไว้ในคำตอบของคุณที่นี่เท่านั้น? ถามราวกับว่าเป็นส่วนหนึ่งของฐานรหัสฉันไม่สามารถค้นหา / นำเข้าได้ :)
Scott Borden


83

วิธีที่มีประสิทธิภาพมากในการดึงข้อมูลคือการรวมความเข้าใจของรายการหรือพจนานุกรมเข้ากับการแบ่งส่วน หากคุณไม่จำเป็นต้องสั่งซื้อสินค้า (คุณต้องการเพียง 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]}

โดยทั่วไปความเข้าใจเช่นนี้จะทำงานได้เร็วกว่าลูป "สำหรับ x ใน 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 เป็นปัญหาหรือไม่หากพจนานุกรมทั้งหมดของฉันพิมพ์ออกมาเมื่อฉันเรียกใช้คำสั่งใด ๆ เหล่านี้
Ted Taylor of Life

list (mydict) [: 2] นั้นสิ้นเปลืองหากคุณไม่จำเป็นต้องเรียงพจนานุกรมและต้องการเพียง 2 องค์ประกอบแรกเท่านั้น จะเกิดอะไรขึ้นถ้าพจนานุกรมมีคู่ 1 ล้าน kv? การแปลงสิ่งทั้งหมดเป็นรายการมีราคาแพง การแก้ปัญหาของ Mark Byers ดีกว่ามาก
JJ

นี่น่าจะเป็นทางออก!
Guenter

14

dictไม่ได้เรียงลำดับ s ของ 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))

ไม่ดูขี้เกียจ. ใช้เวลานานกว่า `list (d.items ()) ถึง 2 เท่า [: 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 ()


2
คำตอบที่ยอดเยี่ยมนี่เป็นคำตอบเดียวในหน้านี้ที่เหมาะกับฉันและยังอ่านได้อีกด้วย นอกจากนี้ฉันสามารถตรวจสอบได้ว่าสิ่งนี้ใช้ได้กับ Python 3 ซึ่งคำตอบเก่า ๆ บางคำตอบไม่ได้
cdahms

7

ไม่เห็นบนนี้ จะไม่ถูกเรียงลำดับ แต่เป็นไวยากรณ์ที่ง่ายที่สุดหากคุณต้องการเพียงแค่นำองค์ประกอบบางอย่างจากพจนานุกรม

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

7
ฉันลองใช้รหัสของคุณ แต่ฉันได้รับข้อผิดพลาดนี้: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (หุ้นเป็นชื่อพจนานุกรมของฉัน)
Moondra

2
@Moondra - ต้องแปลงเป็นรายการก่อนที่จะเรียกใช้รายการพจนานุกรม โค้ดด้านบนบรรทัดจะทำงานถ้า {key: value for key, value in list (d.items ()) [0: n]}
Rajesh Mappu

{A: N สำหรับ (A, N) ใน [x สำหรับ x ใน d.items ()] [: 4]}
farid khafizov

6

ในการรับองค์ประกอบ N อันดับต้น ๆ จากพจนานุกรม python ของคุณคุณสามารถใช้โค้ดบรรทัดต่อไปนี้:

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

ในกรณีของคุณคุณสามารถเปลี่ยนเป็น:

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

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



1

ขึ้นอยู่กับสิ่งที่ 'มีประสิทธิภาพสูงสุด' ในกรณีของคุณ

หากคุณต้องการเพียงแค่ตัวอย่างกึ่งสุ่มของพจนานุกรมขนาดใหญ่fooให้ใช้foo.iteritems()และรับค่าจากมันมากเท่าที่คุณต้องการมันเป็นการดำเนินการที่ขี้เกียจที่จะหลีกเลี่ยงการสร้างรายการคีย์หรือรายการที่ชัดเจน

หากคุณต้องการจัดเรียงคีย์ก่อนไม่มีวิธีใดที่จะใช้สิ่งที่เหมือนkeys = foo.keys(); keys.sort()หรือsorted(foo.iterkeys())คุณจะต้องสร้างรายการคีย์ที่ชัดเจน keysจากนั้นหั่นหรือย้ำผ่านครั้งแรกยังไม่มีข้อความ

BTW ทำไมคุณถึงสนใจวิธีที่ 'มีประสิทธิภาพ'? คุณทำโปรไฟล์โปรแกรมของคุณหรือไม่? หากคุณไม่เคยทำให้ใช้วิธีที่ชัดเจนและเข้าใจง่ายก่อน โอกาสที่จะทำได้ดีโดยไม่กลายเป็นคอขวด


นี่เป็นแอปพลิเคชันสำหรับโปรแกรมทางการเงินและฉันพยายามสร้างโค้ดทุกบรรทัดอย่างมีประสิทธิภาพที่สุด ฉันไม่ได้กำหนดรายละเอียดโปรแกรมและยอมรับว่านี่อาจไม่ใช่คอขวด แต่ฉันต้องการขอวิธีแก้ปัญหาที่มีประสิทธิภาพโดยค่าเริ่มต้น ขอบคุณสำหรับการตอบกลับ.
Jason Strimpel

1

สิ่งนี้อาจไม่สวยหรูมากนัก แต่ก็เหมาะกับฉัน:

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

คุณสามารถเข้าถึงวิธีนี้ได้หลายวิธี หากคำสั่งซื้อมีความสำคัญคุณสามารถทำได้:

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

หากคำสั่งซื้อไม่เป็นปัญหาคุณสามารถทำได้:

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

ในตัวอย่างแรกคุณควรเรียกมันvalueมากกว่าitemเพื่อความชัดเจน
agf

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

ฉันได้ลองคำตอบสองสามข้อด้านบนแล้วและทราบว่าบางคำตอบขึ้นอยู่กับเวอร์ชันและไม่สามารถใช้งานได้ในเวอร์ชัน 3.7

ฉันทราบด้วยว่าตั้งแต่ 3.6 พจนานุกรมทั้งหมดจะเรียงลำดับตามลำดับที่แทรกรายการ

แม้จะมีการสั่งพจนานุกรมตั้งแต่ 3.6 ข้อความบางส่วนที่คุณคาดว่าจะใช้กับโครงสร้างที่สั่งได้ก็ดูเหมือนจะไม่ได้ผล

คำตอบสำหรับคำถาม OP ที่ได้ผลดีที่สุดสำหรับฉัน

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

FYI ช้ากว่า 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) ที่เข้มข้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.