ค้นหารายการวัตถุใน Python


94

สมมติว่าฉันกำลังสร้างคลาสง่ายๆเพื่อให้ทำงานคล้ายกับโครงสร้างแบบ C เพื่อเก็บองค์ประกอบข้อมูลไว้ ฉันกำลังพยายามหาวิธีค้นหารายการวัตถุสำหรับวัตถุที่มีแอตทริบิวต์เท่ากับค่าหนึ่ง ด้านล่างนี้เป็นตัวอย่างเล็กน้อยเพื่อแสดงให้เห็นถึงสิ่งที่ฉันพยายามทำ

ตัวอย่างเช่น:

class Data:
    pass

myList = []

for i in range(20):
    data = Data()
    data.n = i
    data.n_squared = i * i
    myList.append(data)

ฉันจะค้นหารายการ myList เพื่อตรวจสอบว่ามีองค์ประกอบที่มี n == 5 ได้อย่างไร

ฉันใช้ Google และค้นหาเอกสาร Python และฉันคิดว่าฉันอาจสามารถทำสิ่งนี้ได้ด้วยความเข้าใจในรายการ แต่ฉันไม่แน่ใจ ฉันอาจเพิ่มว่าฉันต้องใช้ Python 2.4.3 อยู่แล้วดังนั้นฟีเจอร์ gee-whiz 2.6 หรือ 3.x ใหม่ ๆ จึงไม่สามารถใช้ได้กับฉัน


บางทีอาจเป็นมุมมองที่ไม่ได้ตั้งใจของตัวอย่างของคุณ: myList = [Data (). n == 0, Data (). n = 1, ... ] โดยที่ data.n จะถูกกำหนดโดย range () และ data.n จะเป็น ดัชนีลงใน myList ดังนั้นช่วยให้คุณสามารถดึงอินสแตนซ์ Data () ใด ๆ ขึ้นมาได้เพียงแค่อ้างอิง myList ด้วยค่าดัชนี แน่นอนว่าคุณสามารถแก้ไข myList [0] .n = 5.2 หรือบางอย่างได้ในภายหลัง และตัวอย่างอาจจะง่ายเกินไป
DevPlayer

คำตอบ:


139

คุณสามารถรับรายการองค์ประกอบที่ตรงกันทั้งหมดพร้อมความเข้าใจในรายการ:

[x for x in myList if x.n == 30]  # list of all elements with .n==30

หากคุณเพียงต้องการตรวจสอบว่ารายการมีองค์ประกอบใดที่ตรงและทำได้ (ค่อนข้าง) มีประสิทธิภาพคุณสามารถทำได้

def contains(list, filter):
    for x in list:
        if filter(x):
            return True
    return False

if contains(myList, lambda x: x.n == 3)  # True if any element has .n==3
    # do stuff

25
หรือใด ๆ (custom_filter (x) สำหรับ x ใน myList ถ้า xn == 30) ซึ่งเป็นเพียงฟังก์ชัน "มี" ของคุณในตัว
nosklo

ข้อผิดพลาดทางไวยากรณ์บน nosklo - ต้องการชุด () เพิ่มเติมรอบ ๆ เครื่องกำเนิดไฟฟ้า
gahooa

ไม่เป็นเช่นนั้น ลองใช้งานดู
Robert Rossney

1
จะเป็นการดีที่จะรวมคำตอบนี้เข้ากับ gahooa ( stackoverflow.com/a/598602/2349267 )
Roman Hwang

77

เรียบง่ายสง่างามและทรงพลัง:

นิพจน์เครื่องกำเนิดไฟฟ้าในการเชื่อมต่อกับ builtin ... (python 2.5+)

any(x for x in mylist if x.n == 10)

ใช้ Python any()builtin ซึ่งกำหนดไว้ดังนี้:

any (iterable) -> Return True หากองค์ประกอบใด ๆ ของการทำซ้ำเป็นจริง เทียบเท่ากับ:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False

ดี. FYI คุณสามารถทำอะไรก็ได้ (x สำหรับ x ในรายการของฉันถ้า xn == 10) เพื่อบันทึกบาง parens (เช่นกัน == not =)
Jacob Gabrielson

ฉันชอบใช้any(x for x in mylist if x['n'] == 10)แต่เป็นความคิดที่ดี
Alex Montoya


39
[x for x in myList if x.n == 30]               # list of all matches
[x.n_squared for x in myList if x.n == 30]     # property of matches
any(x.n == 30 for x in myList)                 # if there is any matches
[i for i,x in enumerate(myList) if x.n == 30]  # indices of all matches

def first(iterable, default=None):
  for item in iterable:
    return item
  return default

first(x for x in myList if x.n == 30)          # the first match, if any

1
นี่เป็นคำตอบที่ดีเนื่องจากวิธี "แรก" ซึ่งน่าจะเป็นกรณีการใช้งานที่พบบ่อยที่สุด
galarant

ดีมากขอบคุณ! ดัชนีการจับคู่คือสิ่งที่ฉันกำลังมองหา มีทางลัดที่จะใช้เพื่อจัดทำดัชนีรายการโดยตรงเพื่อเข้าถึงฟิลด์อื่นหรือไม่? ตอนนี้ฉันได้รับรายชื่อรายการ (มีเพียงรายการเดียวดังนั้นจึงเป็นรายการที่มีรายการเดียว) ในการรับดัชนีฉันต้องดำเนินการผลลัพธ์ [0] ก่อนจึงจะสามารถใช้ดัชนีนี้เพื่อจัดทำดัชนีรายการได้ จากตัวอย่างคำถามฉันต้องการเข้าถึง n_squared จาก n: myList [ดัชนีของ myList.n == 5] .n_squared
Frieke

32
filter(lambda x: x.n == 5, myList)

25
สำหรับผู้ที่ต้องการเรียนภาษา Python การทำความเข้าใจแลมด้าเป็นพื้นฐาน
vartec

2
ใช่และไม่ใช่ - ด้วยความเข้าใจในรายการและการเรียงลำดับผู้สร้างฟังก์ชันหลักเช่น operator.attrgetter ฉันแทบจะไม่เคยใช้lambdas เลย
Ben Hoyt

9

คุณสามารถใช้inเพื่อค้นหาไอเท็มในคอลเลกชั่นและความเข้าใจของรายการเพื่อแยกฟิลด์ที่คุณสนใจสิ่งนี้ (ใช้ได้กับรายการเซ็ตทูเพิลและอะไรก็ตามที่กำหนด__contains__หรือ__getitem__)

if 5 in [data.n for data in myList]:
    print "Found it"

ดูสิ่งนี้ด้วย:


4

คุณควรเพิ่ม a __eq__และ__hash__method ลงในDataคลาสของคุณซึ่งจะตรวจสอบได้ว่า__dict__แอตทริบิวต์เท่ากันหรือไม่ (คุณสมบัติเดียวกัน) จากนั้นค่าของมันจะเท่ากันหรือไม่

หากคุณทำเช่นนั้นคุณสามารถใช้ไฟล์

test = Data()
test.n = 5

found = test in myList

inการตรวจสอบคำหลักถ้าอยู่ในtestmyList

หากคุณต้องการเพียงnคุณสมบัติในDataคุณสามารถใช้:

class Data(object):
    __slots__ = ['n']
    def __init__(self, n):
        self.n = n
    def __eq__(self, other):
        if not isinstance(other, Data):
            return False
        if self.n != other.n:
            return False
        return True
    def __hash__(self):
        return self.n

    myList = [ Data(1), Data(2), Data(3) ]
    Data(2) in myList  #==> True
    Data(5) in myList  #==> False

3

พิจารณาใช้พจนานุกรม:

myDict = {}

for i in range(20):
    myDict[i] = i * i

print(5 in myDict)

หรือ: d = dict ((i, i * i) สำหรับ i ในช่วง (20))
hughdbrown

มันช่วยแก้ปัญหาเล็กน้อยที่ฉันใช้ในการอธิบายคำถามของฉัน แต่ไม่ได้แก้ปัญหาที่แท้จริงของฉัน คำตอบที่ฉันกำลังมองหา (5+ ปีที่แล้ว) คือความเข้าใจในรายการ :)
m0j0

1

อีกวิธีหนึ่งที่คุณสามารถทำได้คือใช้ฟังก์ชัน next ()

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