ทำไมรหัสการเพิ่มลิสต์แบบวนซ้ำนี้จึงทำให้ดัชนีการกำหนดรายการอยู่นอกช่วง?


194

โปรดพิจารณารหัสต่อไปนี้:

i = [1, 2, 3, 5, 8, 13]
j = []
k = 0

for l in i:
    j[k] = l
    k += 1

print j

ผลลัพธ์ (Python 2.6.6 บน Win 7 32- บิต) คือ:

> Traceback (most recent call last): 
>     j[k] = l IndexError: list assignment index out of range

ฉันคิดว่ามันเป็นอะไรที่เรียบง่ายที่ฉันไม่เข้าใจ บางคนสามารถล้างมันได้หรือไม่


7
appendเป็นโซลูชั่นที่เหมาะสมสำหรับกรณีการใช้งานของคุณอย่างไรก็ตามมีวิธีการแทรกในรายการหลามซึ่งสามารถแทรกโดยตรงไปยังตำแหน่งที่ฉันอยู่ในรายการ j.insert(k, l)
opensourcegeek

ฉันขอถามได้ไหมว่าทำไมโซลูชั่นของ OP ถึงไม่ทำงาน ทำไมต้องใช้ผนวก
เฮเลน

คำตอบ:


317

jเป็นรายการที่ว่างเปล่า แต่คุณกำลังพยายามเขียนถึงองค์ประกอบ[0]ในการทำซ้ำครั้งแรกซึ่งยังไม่มี

ลองทำสิ่งต่อไปนี้แทนเพื่อเพิ่มองค์ประกอบใหม่ในตอนท้ายของรายการ:

for l in i:
    j.append(l)

แน่นอนว่าคุณไม่เคยทำสิ่งนี้ในทางปฏิบัติหากสิ่งที่คุณต้องการทำคือการคัดลอกรายการที่มีอยู่ คุณแค่ทำ:

j = list(i)

อีกทางเลือกหนึ่งถ้าคุณต้องการใช้รายการ Python เช่นอาร์เรย์ในภาษาอื่นคุณสามารถสร้างรายการล่วงหน้าด้วยองค์ประกอบที่ตั้งไว้เป็นค่า Null ( Noneในตัวอย่างด้านล่าง) และหลังจากนั้นเขียนทับค่าในตำแหน่งที่ต้องการ:

i = [1, 2, 3, 5, 8, 13]
j = [None] * len(i)
#j == [None, None, None, None, None, None]
k = 0

for l in i:
   j[k] = l
   k += 1

สิ่งที่ต้องตระหนักคือlistวัตถุจะไม่อนุญาตให้คุณกำหนดค่าให้กับดัชนีที่ไม่มีอยู่


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

ฉันเห็นว่าสิ่งนี้อาจสร้างความสับสนให้กับผู้ที่มาจากภาษาอื่นเช่น PHP หรือ C. j เป็นประเภทรายการไม่ใช่อาร์เรย์ ด้วยประเภทรายการฉันไม่คิดว่ามันจะสามารถถอดได้ สับสนมากถ้ามาจากภาษาอื่น
al

@Nguaial ชนิดรายการสามารถย่อยได้ แต่คุณสามารถเข้าถึงองค์ประกอบที่มีอยู่แล้วเท่านั้น - คุณไม่สามารถสร้างองค์ประกอบโดยพยายามเขียนไปยังดัชนีที่อยู่นอกช่วง j [0] = "foo" จะทำงานถ้ารายการมีองค์ประกอบอย่างน้อยหนึ่งรายการ
Steve Mayne

52

ตัวเลือกอื่นของคุณคือการเริ่มต้นj:

j = [None] * len(i)

3
คุณต้องการใช้ len (i) มากกว่า max
Steve Mayne

25

ทำj.append(l)แทนj[k] = lและหลีกเลี่ยงkเลย


2
วิธีที่สั้นกว่า (Pythonic มากขึ้น) อาจเป็นj+=[l]
Oleh Prypin

2
@BlaXpirit: มันจะสร้างภาระให้กับนักเก็บขยะฉันคิดว่า
khachik

2
@ BalXpirit: เนื่องจากมันช่วยประหยัดอักขระได้ไม่กี่ตัว (โดยเฉพาะเมื่อคุณต้องเพิ่มช่องว่างเพื่อให้เป็นที่ยอมรับ) และนั่น.appendก็เป็นเรื่องที่พบได้บ่อยกว่า (อาจเป็นเพราะเหตุผล - ฉันคิดว่ามันเข้าใจง่ายกว่าเล็กน้อย) ในทางใดทางหนึ่ง. (แก้ไข @khachik: ไม่+=แก้ไขในสถานที่)

15

คุณสามารถใช้ list comprehension:

j = [l for l in i]

หรือทำสำเนาโดยใช้คำสั่ง:

j = i[:]

การก่อสร้างที่สองนั้นเรียบร้อย
javadba

2
หากเป้าหมายเดียวคือคัดลอกรายการคุณสามารถพูดได้ว่า j = list (i) ฉันคิดว่าคำถามนั้นเกี่ยวกับพฤติกรรมของรายการมากกว่าที่ต้องการวิธีคัดลอกองค์ประกอบโดยเฉพาะ
Steve Mayne

10
j.append(l)

นอกจากนี้หลีกเลี่ยงการใช้ตัวพิมพ์เล็ก "L" เพราะมันง่ายสำหรับพวกเขาที่จะสับสนกับ 1


7

ฉันคิดว่าการแทรกวิธี Python เป็นสิ่งที่คุณกำลังมองหา:

แทรกองค์ประกอบ x ที่ตำแหน่ง i list.insert (i, x)

array = [1,2,3,4,5]

array.insert(1,20)

print(array)

# prints [1,2,20,3,4,5]

1
ไม่มีจุดใช้insertเมื่อappendจัดทำขึ้นโดยเฉพาะสำหรับจุดประสงค์นี้
holdenweb

ในความเป็นจริงรหัสของคุณจะพิมพ์[1, 20, 2, 3, 4, 5]ออกมา
holdenweb

คุณแทรกที่ดัชนี 1 แทนที่ดัชนี 1 และเป็นต้นไป ค่าที่แทรกไม่ได้จบที่ดัชนี 2 Iist.insert () จำเป็นสำหรับคุณเมื่อคุณไม่ต้องการเพิ่มรายการในตอนท้ายของรายการเท่านั้น คำถามที่นี่ทำตรงนั้นเพื่อให้ list.append () ดีกว่า
Martijn Pieters

จริงๆแล้วทำไมฉันตอบคำถามนี้เหมือนที่ฉันประหลาดใจด้วย: D ไม่ทราบว่าฉันคิดอย่างไร :) นี่คือ "list.append ()" ซึ่งเป็นคำตอบที่ได้รับการยอมรับ ฉันคิดว่ามันช่วยให้ผู้คนหรือให้ความคิดในการแก้ปัญหาของพวกเขาเพื่อให้ได้ 5 ครั้ง
เมห์เม็ตคาเกนคายาลป์

5

คุณสามารถใช้พจนานุกรม (คล้ายกับอาร์เรย์ที่เชื่อมโยง) สำหรับ j

i = [1, 2, 3, 5, 8, 13]
j = {} #initiate as dictionary
k = 0

for l in i:
    j[k] = l
    k += 1

print j

จะพิมพ์:

{0: 1, 1: 2, 2: 3, 3: 5, 4: 8, 5: 13}

สำหรับตัวบ่งชี้ที่ต่อเนื่องกันเริ่มต้นที่ 0 การแมปมักจะเป็นโครงสร้างข้อมูลที่ผิดโดยเฉพาะอย่างยิ่งเมื่อการแมปไม่มีการแบ่งส่วนหรือย้อนกลับเนื่องจากไม่ได้มีจุดประสงค์เพื่อถ่ายทอดคำสั่งเฉพาะ
Martijn Pieters

2

อีกวิธีหนึ่ง:

j=i[0]
for k in range(1,len(i)):
    j = numpy.vstack([j,i[k]])

ในกรณีนี้jจะเป็นอาร์เรย์ที่มีจำนวนมาก


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