Python ชุด vs รายการ


187

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

คำตอบ:


231

ขึ้นอยู่กับสิ่งที่คุณตั้งใจจะทำ

ชุดจะเร็วขึ้นอย่างมีนัยสำคัญเมื่อพูดถึงการพิจารณาว่ามีวัตถุอยู่ในชุด (เหมือนในx in s) แต่ช้ากว่ารายการเมื่อต้องทำซ้ำเนื้อหา

คุณสามารถใช้โมดูล timeitเพื่อดูว่าสถานการณ์ของคุณเร็วแค่ไหน


4
สำหรับประเด็นของคุณ: "ชุดเร็วขึ้นอย่างมาก" การใช้งานพื้นฐานที่ทำให้เร็วขึ้นคืออะไร
แลกเปลี่ยน

ภาษาสคริปต์ต้องการซ่อนการใช้งานพื้นฐาน แต่ความเรียบง่ายที่เห็นได้ชัดนี้ไม่ใช่สิ่งที่ดีเสมอไปคุณจำเป็นต้องมีการรับรู้ 'โครงสร้างข้อมูล' เมื่อคุณออกแบบซอฟต์แวร์
Christophe Roussy

4
ชุดไม่ช้ากว่ารายการอย่างมากในขณะที่วนซ้ำ
omerfarukdogan

39
ชุดและรายการทั้งสองมีการวนซ้ำเวลาเชิงเส้น จะบอกว่าหนึ่งคือ "ช้าลง" กว่าคนอื่นเข้าใจผิดและมีความสับสนโปรแกรมเมอร์ใหม่ที่อ่านคำตอบนี้
habnabit

@habnabit หากคุณกำลังบอกว่าพวกเขาทั้งสองมีการทำซ้ำเวลาเชิงเส้น นี่หมายความว่าพวกเขามีเวลาทำซ้ำเท่ากันหรือไม่? ความแตกต่างคืออะไร?
Mohammed Noureldin

153

รายการเร็วกว่าชุดเล็กน้อยเมื่อคุณต้องการวนซ้ำค่า

อย่างไรก็ตามชุดจะเร็วกว่ารายการมากหากคุณต้องการตรวจสอบว่ามีรายการอยู่ในชุดนั้นหรือไม่ พวกเขาสามารถมีรายการที่ไม่ซ้ำกันเท่านั้น

ปรากฎว่าสิ่งอันดับ tuples ดำเนินการในลักษณะเดียวกับรายการยกเว้นการเปลี่ยนแปลงไม่ได้

iterating

>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

ตรวจสอบว่ามีวัตถุ

>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404

6
ฉันพบว่า (ชุดเริ่มต้น -> 5.5300979614257812) (เริ่มต้นรายการ -> 1.8846848011016846) (ค่าเริ่มต้น tuple -> 1.8730108737945557) รายการขนาด 10,000 ใน intel core i5 quad core ของฉันกับ 12GB RAM ควรคำนึงถึงเรื่องนี้ด้วย
ThePracticalOne

4
ฉันได้อัปเดตรหัสเพื่อลบการสร้างวัตถุตอนนี้ ขั้นตอนการตั้งค่าของ timeit ลูปจะถูกเรียกเพียงครั้งเดียว ( docs.python.org/2/library/timeit.html#timeit.Timer.timeit )
Ellis Percival

7

รายการประสิทธิภาพ:

>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

ตั้งค่าประสิทธิภาพ:

>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

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

เซตเป็นโครงสร้างลำดับ แต่มีสองความแตกต่างจากรายการและสิ่งอันดับ ถึงแม้ว่าเซตจะมีคำสั่งอยู่ก็ตามคำสั่งนั้นเป็นกฎเกณฑ์และไม่อยู่ในการควบคุมของโปรแกรมเมอร์ ข้อแตกต่างที่สองคือองค์ประกอบในชุดต้องไม่ซ้ำกัน

setตามคำจำกัดความ [ python | วิกิ ]

>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}

4
ปิดครั้งแรกคุณควรอัปเดตsetในตัวประเภทการเชื่อมโยง ( docs.python.org/2/library/stdtypes.html#set ) ไม่ได้เลิกใช้setsห้องสมุด ประการที่สอง "เซ็ตเป็นโครงสร้างลำดับ" อ่านสิ่งต่อไปนี้จากลิงค์ประเภทบิวด์อิน: "เป็นคอลเล็กชั่นที่ไม่เรียงลำดับชุดไม่บันทึกตำแหน่งองค์ประกอบหรือลำดับการแทรกดังนั้นชุดไม่รองรับการจัดทำดัชนีการแบ่งส่วนหรืออื่น ๆ พฤติกรรมเหมือนลำดับ "
Seaux

7
rangelistไม่ใช่ rangeเป็นคลาสพิเศษที่มี__contains__วิธีเวทมนต์ที่กำหนดเอง
Ryne Wang

@RyneWang นี่เป็นเรื่องจริง แต่สำหรับ Python3 เท่านั้น ในช่วง Python2 ส่งคืนรายการปกติ (นั่นคือเหตุผลที่มีสิ่งที่น่ากลัวเช่นนี้อยู่xrange)
Manoel Vilela

7

Setชนะเนื่องจากเช็คที่อยู่ใกล้ทันทีมี: https://en.wikipedia.org/wiki/Hash_table

การใช้งานรายการ : โดยปกติจะเป็นอาร์เรย์ระดับต่ำใกล้กับโลหะเหมาะสำหรับการทำซ้ำและเข้าถึงแบบสุ่มโดยใช้ดัชนีองค์ประกอบ

Set Implementation: https://en.wikipedia.org/wiki/Hash_tableมันไม่ได้วนซ้ำในรายการ แต่ค้นหาองค์ประกอบโดยการคำนวณแฮชจากกุญแจดังนั้นจึงขึ้นอยู่กับลักษณะขององค์ประกอบสำคัญและแฮช ฟังก์ชัน คล้ายกับสิ่งที่ใช้สำหรับ dict ฉันสงสัยว่าlistอาจเร็วขึ้นหากคุณมีองค์ประกอบน้อยมาก (<5) องค์ประกอบที่มีขนาดใหญ่กว่าsetจะนับว่าเช็คนั้นมีประสิทธิภาพดีกว่า นอกจากนี้ยังรวดเร็วสำหรับการเพิ่มและลบองค์ประกอบ โปรดระลึกไว้เสมอว่าการสร้างชุดมีค่าใช้จ่าย!

หมายเหตุ : หากlistมีการเรียงลำดับแล้วการค้นหาlistอาจจะค่อนข้างเร็ว แต่สำหรับกรณีปกติ a setจะเร็วกว่าและง่ายกว่าสำหรับมีการตรวจสอบ


8
ใกล้กับโลหะเหรอ? มันหมายความว่าอย่างไรในบริบทของ Python รายการใกล้ชิดกับโลหะมากกว่าชุดอย่างไร
roganjosh

@roganjosh, python ยังคงทำงานบนเครื่องและการใช้งานบางอย่างเช่นรายการ 'array' นั้นใกล้เคียงกับฮาร์ดแวร์ที่ดี: stackoverflow.com/questions/176011/แต่มันก็ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำ เป็นเรื่องดีที่จะรู้เพียงเล็กน้อยเกี่ยวกับการติดตั้งใช้งานไม่ได้เป็นเพียงนามธรรม
Christophe Roussy

2

TL; DR

โครงสร้างข้อมูล (DS) มีความสำคัญเพราะพวกเขาจะใช้ในการดำเนินการกับข้อมูลซึ่งโดยทั่วไปหมายถึง: นำเข้าบาง , กระบวนการมันและให้กลับไปเอาท์พุท

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

รายการ

รายชื่อเป็นลำดับที่ไม่แน่นอน , มักจะใช้ในการจัดเก็บคอลเลกชันของรายการที่เป็นเนื้อเดียวกัน

ชุด

วัตถุชุดเป็นคอลเลกชันเรียงลำดับของวัตถุ hashable ที่แตกต่างกัน โดยทั่วไปจะใช้เพื่อทดสอบการเป็นสมาชิกลบรายการที่ซ้ำกันออกจากลำดับและคำนวณการดำเนินการทางคณิตศาสตร์เช่นการแยกการรวมกันความแตกต่างและความแตกต่างแบบสมมาตร

การใช้

จากคำตอบบางข้อเป็นที่ชัดเจนว่ารายการนั้นค่อนข้างเร็วกว่าชุดเมื่อทำการวนซ้ำค่าต่างๆ ในทางกลับกันชุดจะเร็วกว่ารายการเมื่อตรวจสอบว่ามีรายการอยู่ภายในหรือไม่ ดังนั้นสิ่งเดียวที่คุณสามารถพูดได้คือรายการดีกว่าชุดสำหรับการดำเนินการบางอย่างและในทางกลับกัน


2

ฉันสนใจผลลัพธ์เมื่อตรวจสอบด้วย CPython หากค่าเป็นหนึ่งในตัวอักษรจำนวนน้อย setชนะในหลาม 3 VS tuple, listและor:

from timeit import timeit

def in_test1():
  for i in range(1000):
    if i in (314, 628):
      pass

def in_test2():
  for i in range(1000):
    if i in [314, 628]:
      pass

def in_test3():
  for i in range(1000):
    if i in {314, 628}:
      pass

def in_test4():
  for i in range(1000):
    if i == 314 or i == 628:
      pass

print("tuple")
print(timeit("in_test1()", setup="from __main__ import in_test1", number=100000))
print("list")
print(timeit("in_test2()", setup="from __main__ import in_test2", number=100000))
print("set")
print(timeit("in_test3()", setup="from __main__ import in_test3", number=100000))
print("or")
print(timeit("in_test4()", setup="from __main__ import in_test4", number=100000))

เอาท์พุท:

tuple
4.735646052286029
list
4.7308746771886945
set
3.5755991376936436
or
4.687681658193469

สำหรับ 3 ถึง 5 ตัวอักษรsetยังคงชนะด้วยระยะขอบกว้างและorกลายเป็นช้าที่สุด

ใน Python 2 setนั้นช้าที่สุดเสมอ orเป็นเร็วที่สุดสำหรับ 2 ถึง 3 ตัวอักษรtupleและlistเร็วกว่าด้วยตัวอักษร 4 ตัวขึ้นไป ฉันไม่สามารถแยกแยะความแตกต่างของความเร็วเทียบกับtuplelist

เมื่อค่าที่จะทดสอบถูกแคชในตัวแปรโกลบอลจากฟังก์ชันแทนที่จะสร้างตัวอักษรภายในลูปsetจะชนะทุกครั้งแม้ใน Python 2

ผลลัพธ์เหล่านี้ใช้กับ CPython แบบ 64 บิตบน Core i7


0

ฉันจะแนะนำชุดการใช้งานที่กรณีการใช้งานมีข้อ จำกัด ในการอ้างอิงหรือค้นหาการมีอยู่และการใช้ Tuple ซึ่งกรณีการใช้งานต้องการให้คุณทำซ้ำ รายการเป็นการใช้งานในระดับต่ำและต้องใช้หน่วยความจำอย่างมีนัยสำคัญ


1
แน่นอนความแตกต่างที่เหมาะสมระหว่างเวลาที่จะใช้ชุดและเมื่อใช้ Tuple มีความสำคัญสูงสุด ฉันจะไม่กังวลเกี่ยวกับค่าใช้จ่ายในหน่วยความจำที่เกี่ยวข้องรอยเท้าเว้นแต่ฉันจะเขียนสคริปต์ API ระดับต่ำกว่า

0
from datetime import datetime
listA = range(10000000)
setA = set(listA)
tupA = tuple(listA)
#Source Code

def calc(data, type):
start = datetime.now()
if data in type:
print ""
end = datetime.now()
print end-start

calc(9999, listA)
calc(9999, tupA)
calc(9999, setA)

เอาท์พุทหลังจากเปรียบเทียบ 10 ซ้ำสำหรับทั้ง 3: การเปรียบเทียบ


0

ชุดเร็วขึ้นคุณจะได้รับฟังก์ชั่นเพิ่มเติมจากชุดเช่นสมมติว่าคุณมีสองชุด:

set1 = {"Harry Potter", "James Bond", "Iron Man"}
set2 = {"Captain America", "Black Widow", "Hulk", "Harry Potter", "James Bond"}

เราสามารถเข้าร่วมสองชุดได้อย่างง่ายดาย:

set3 = set1.union(set2)

ค้นหาสิ่งที่เป็นเรื่องปกติในทั้งสอง:

set3 = set1.intersection(set2)

ค้นหาสิ่งที่แตกต่างกันทั้ง:

set3 = set1.difference(set2)

และอีกมากมาย! เพียงลองพวกเขาพวกเขาสนุก! ยิ่งกว่านั้นถ้าคุณต้องทำงานกับค่าต่าง ๆ ภายใน 2 รายการหรือค่าทั่วไปภายใน 2 รายการฉันชอบที่จะแปลงรายการของคุณเป็นชุดและโปรแกรมเมอร์หลายคนทำเช่นนั้น หวังว่าจะช่วยให้คุณ :-)

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