Bu yanıt başlangıçta yinelenen olarak işaretlenmiş bir soruya yanıt olarak yazılmıştır:
Python'daki listeden koordinatları kaldırma
Kodunuzda iki sorun var:
1) remove () kullanırken, tamsayıları kaldırmayı denerken, bir tuple kaldırmanız gerekir.
2) for döngüsü listenizdeki öğeleri atlar.
Kodunuzu yürüttüğümüzde neler olacağını inceleyelim:
>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
... if a < 0 or b < 0:
... L1.remove(a,b)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)
İlk sorun, kaldırılacak () için hem 'a' hem de 'b' iletiyorsunuz, ancak remove () yalnızca tek bir argümanı kabul ediyor. Öyleyse listenizle düzgün bir şekilde çalışmak için remove () yöntemini nasıl alabiliriz? Listenizdeki her bir öğenin ne olduğunu bulmamız gerekiyor. Bu durumda, her biri bir demettir. Bunu görmek için listenin bir öğesine erişelim (indeksleme 0'dan başlar):
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
Aha! L1'in her elemanı aslında bir demettir. Kaldırmak için geçmemiz gereken şey budur (). Python'daki tuples çok kolaydır, sadece değerleri parantez içine alarak yapılırlar. "a, b" bir demet değil, "(a, b)" bir demettir. Kodunuzu değiştirip tekrar çalıştırıyoruz:
# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))
Bu kod hatasız çalışır, ancak çıktığı listeye bakalım:
L1 is now: [(1, 2), (5, 6), (1, -2)]
(1, -2) neden hala listenizde? Üzerinde yineleme yapmak için bir döngü kullanırken listeyi değiştirmek, özel bir bakım gerektirmeden çok kötü bir fikirdir. (1, -2) öğesinin listede kalmasının nedeni, listedeki her öğenin konumlarının for döngüsünün yinelemeleri arasında değişmesidir. Yukarıdaki kodu daha uzun bir liste halinde beslersek ne olduğuna bakalım:
L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Bu sonuçtan çıkarım yapabileceğiniz gibi, koşullu ifadenin her doğru olarak değerlendirildiği ve bir liste öğesinin kaldırıldığı her seferinde, döngünün bir sonraki yinelemesi, değerleri artık farklı endekslerde yer aldığından listedeki bir sonraki öğenin değerlendirmesini atlayacaktır.
En sezgisel çözüm listeyi kopyalamak, daha sonra orijinal listeyi tekrarlamak ve yalnızca kopyayı değiştirmek. Bunu böyle deneyebilirsiniz:
L2 = L1
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)
Ancak, çıktı aşağıdakilerle aynı olacaktır:
'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Bunun nedeni, L2'yi oluşturduğumuzda, python'un aslında yeni bir nesne oluşturmadığıdır. Bunun yerine, yalnızca L2'yi L1 ile aynı nesneye göndermiştir. Bunu sadece "eşittir" (==) 'den farklı olan' is 'ile doğrulayabiliriz.
>>> L2=L1
>>> L1 is L2
True
Copy.copy () kullanarak gerçek bir kopya oluşturabiliriz. Sonra her şey beklendiği gibi çalışır:
import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
Son olarak, tamamen yeni bir L1 kopyası yapmaktan daha temiz bir çözüm var. Reversed () işlevi:
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
if a < 0 or b < 0 :
L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
Ne yazık ki, tersine () nasıl çalıştığını yeterince tanımlayamıyorum. Bir liste iletildiğinde bir 'listreverseiterator' nesnesi döndürür. Pratik amaçlar için, argümanının ters kopyasını oluşturmak olarak düşünebilirsiniz. Önerdiğim çözüm bu.