ตอนนี้ฉันรู้ว่ามันไม่ปลอดภัยที่จะแก้ไขรายการในระหว่างการวนซ้ำซ้ำ อย่างไรก็ตามสมมติว่าฉันมีรายการของสตริงและฉันต้องการแยกสตริงเอง การแทนที่ค่าที่เปลี่ยนแปลงไม่ได้จะนับเป็นการเปลี่ยนแปลงหรือไม่?
ตอนนี้ฉันรู้ว่ามันไม่ปลอดภัยที่จะแก้ไขรายการในระหว่างการวนซ้ำซ้ำ อย่างไรก็ตามสมมติว่าฉันมีรายการของสตริงและฉันต้องการแยกสตริงเอง การแทนที่ค่าที่เปลี่ยนแปลงไม่ได้จะนับเป็นการเปลี่ยนแปลงหรือไม่?
คำตอบ:
มันถือว่าเป็นรูปแบบที่ไม่ดี ใช้รายการความเข้าใจแทนด้วยการกำหนดชิ้นถ้าคุณต้องการเก็บการอ้างอิงที่มีอยู่ไปยังรายการ
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
print bคำสั่งถูกดำเนินการคุณสามารถบอกได้ว่าaได้รับการแก้ไขในสถานที่แทนที่จะถูกแทนที่ ความเป็นไปได้อีกอย่างหนึ่งคือการprint b is aดูว่าพวกเขาทั้งคู่ยังคงอ้างถึงวัตถุเดียวกันหรือไม่
เนื่องจากลูปด้านล่างปรับเปลี่ยนองค์ประกอบที่เห็นแล้วเท่านั้นจึงจะถือว่าเป็นที่ยอมรับได้:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
ซึ่งแตกต่างจาก:
a[:] = [s.strip() for s in a]
ตรงที่มันไม่ต้องการการสร้างรายการชั่วคราวและการกำหนดของมันเพื่อแทนที่ต้นฉบับแม้ว่ามันจะต้องมีการทำดัชนีมากขึ้น
ข้อควรระวัง:แม้ว่าคุณจะสามารถแก้ไขรายการได้ด้วยวิธีนี้ แต่คุณไม่สามารถเปลี่ยนจำนวนรายการได้listโดยไม่ต้องเสี่ยงกับโอกาสที่จะประสบปัญหา
นี่คือตัวอย่างของสิ่งที่ฉันหมายถึง - การลบรายการทำให้การจัดทำดัชนียุ่งเหยิงจากจุดนั้น:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(ผลลัพธ์ไม่ถูกต้องเนื่องจากไม่ได้ลบรายการทั้งหมดที่ควรมี)
ปรับปรุง
เนื่องจากนี่เป็นคำตอบที่ได้รับความนิยมค่อนข้างต่อไปนี้เป็นวิธีการลบรายการ "ในสถานที่" อย่างมีประสิทธิภาพ (แม้ว่าจะไม่ใช่คำถาม)
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
for i in aเท่านั้น นี่เป็นสิ่งที่ขัดกับความเป็นจริงมากดูเหมือนจะแตกต่างจากภาษาอื่นและทำให้เกิดข้อผิดพลาดในรหัสของฉันที่ฉันต้องแก้จุดบกพร่องเป็นเวลานาน Python Tutorial ไม่ได้พูดถึงมัน แม้ว่าจะต้องมีเหตุผลบางอย่างหรือไม่
a[i]และs) สำหรับวัตถุเดียวกันในบรรทัดเดียวกันเมื่อคุณไม่ต้องการ a[i] = a[i].strip()ฉันชอบที่จะทำ
a[i] = s.strip()ทำดัชนีเพียงครั้งเดียว
enumerate(b) a[i] =AFAIK เป็นไปไม่ได้ที่จะใช้ลูปนี้ใน Python ด้วยการดำเนินการสร้างดัชนีเพียง 1 ครั้งต่อการวนซ้ำของลูป :(
อีกหนึ่งสำหรับตัวแปรลูปดูดีกว่าฉันด้วย enumerate ():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
range(len(list))ใน Python และมีกลิ่นรหัส
enumerateเป็นตัวกำเนิดที่ไม่ได้สร้าง list.of tuples มันจะสร้างมันทีละตัวเมื่อมันวนซ้ำตามรายการ วิธีเดียวที่จะบอกได้ว่าอะไรจะช้ากว่าtimeitกัน
การแก้ไขแต่ละองค์ประกอบในขณะที่วนรายการเป็นเรื่องปกติตราบใดที่คุณไม่เปลี่ยนองค์ประกอบเพิ่ม / ลบในรายการ
คุณสามารถใช้ list comprehension:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
หรือเพียงแค่ทำC-styleเพื่อห่วง:
for index, item in enumerate(l):
l[index] = item.strip()
ไม่คุณจะไม่เปลี่ยน "เนื้อหา" ของรายการหากคุณสามารถกลายพันธุ์สตริงได้ แต่ในงูหลามพวกเขาไม่สามารถเปลี่ยนแปลงได้ การดำเนินการกับสตริงใด ๆ ส่งคืนสตริงใหม่
หากคุณมีรายการของวัตถุที่คุณรู้ว่าไม่แน่นอนคุณสามารถทำสิ่งนี้ได้ตราบใดที่คุณไม่เปลี่ยนเนื้อหาจริงของรายการ
ดังนั้นคุณจะต้องทำแผนที่บางอย่าง ถ้าคุณใช้นิพจน์ตัวสร้างมัน [การดำเนินการ] จะทำเมื่อคุณวนซ้ำและคุณจะประหยัดหน่วยความจำ
คุณสามารถทำสิ่งนี้:
a = [1,2,3,4,5]
b = [i**2 for i in a]
มันเรียกว่า list comprehension เพื่อให้คุณวนลูปในรายการได้ง่ายขึ้น
คำตอบที่ได้รับจาก Jemshit Iskenderov และ Ignacio Vazquez-Abrams นั้นดีมาก มันสามารถอธิบายเพิ่มเติมด้วยตัวอย่างนี้ลองจินตนาการว่า
a) รายการที่มีเวกเตอร์สองตัวมอบให้คุณ
b) คุณต้องการสำรวจรายการและย้อนกลับลำดับของแต่ละอาร์เรย์
สมมติว่าคุณมี
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # this command does not reverse the string
print([v,b])
คุณจะได้รับ
[array([1, 2, 3, 4]), array([3, 4, 6])]
ในทางกลับกันถ้าคุณทำ
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # this command reverses the string
print([v,b])
ผลที่ได้คือ
[array([4, 3, 2, 1]), array([6, 4, 3])]
ไม่ชัดเจนจากคำถามของคุณว่าเกณฑ์ในการตัดสินใจว่าจะลบสตริงอะไร แต่ถ้าคุณมีหรือสามารถสร้างรายการสตริงที่คุณต้องการลบคุณสามารถทำสิ่งต่อไปนี้:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
ซึ่งเปลี่ยน my_strings เป็น ['a', 'c', 'e']
ในระยะสั้นที่จะทำการแก้ไขในรายการในขณะที่ซ้ำรายการเดียวกัน
list[:] = ["Modify the list" for each_element in list "Condition Check"]
ตัวอย่าง:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]