2016-04-06 16 views
0

Bunu nasıl yapacağımı biliyorum, ama işemek oldukça pythonic görünmüyor. Bunu yapmanın daha temiz bir yolu var mı? (Olduğu istediğin hale)Üzerine yineleme yaparken bir liste düzenleyin (pythonic yol!)

arr = list(range(10)) 
print(arr) 
for n in range(len(arr)): 
    # Perform som operation on the element that changes the value "in place" 
    arr[n] += 1 
print(arr) 

Çıktı:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

cevap

3

onlar söylediklerin. Eğer Listeyi oluştururken ederken operasyon yapmak istiyorsanız yapabileceğiniz:

arr = [u + 1 for u in range(10)] 

I (sürece Python 2 kullanıyorsanız, o zaman xrange için range değiştirmek Python 3. kullandığınız tahmin Python 2 range işlevi gerçek bir list döndürdüğü için liste boyutu çok küçüktür, ancak xrange bir yineleyici döndürür; Python 3 range işlevi, eski xrange (ancak birkaç iyileştirme ile) benzeri bir yineleyici döndürür.

arr varsa bir yeni list nesne ile şimdiki list nesneyi değiştirmeden değiştirmek istediğiniz list mevcut yapabileceğiniz edilir

arr[:] = [u + 1 for u in arr] 
İşte

arr kullanma arasındaki fark gösterilmektedir bazı kod ve ödevin sol tarafında arr[:].

arr = list(range(10)) 
b = arr 
print(id(arr), id(b)) 
arr = [u + 1 for u in arr] 
print(id(arr), id(b)) 
print(arr, b) 

c = arr 
print(id(arr), id(c)) 
arr[:] = [u + 1 for u in arr] 
print(id(arr), id(c)) 
print(arr, c) 

çıkış

3073636268 3073636268 
3073629964 3073636268 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
3073629964 3073629964 
3073629964 3073629964 
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 

Yani arr = [u + 1 for u in arr] Yeni bir liste nesnesine adını arr bağlar, ancak arr[:] = [u + 1 for u in arr] etkin mevcut liste nesnesi dönüşüyor. "Başlık altında" yeni bir geçici liste nesnesi oluşturur ve daha sonra içeriğini eski liste nesnesine kopyalar.

+0

Yani ikincisi verimli mi? – Clausen

+0

@Clausen: Aslında, aslında arr = [u + arr] için u + 1 yapmaktan biraz daha yavaştır, ancak liste büyük değilse hız farkını göremezsiniz. Ama arr [:] = 'işlevini kullanmanın en büyük avantajı, 'arr' için birden fazla referansınız varsa, Martijn'in cevabında açıkladığı gibi, geçerli olmaya devam edecektir. Eğer sadece 'arr = 'kullanırsanız, o zaman diğer referanslar güncel verilere değil, eski verilere ait olacaktır. –

+0

@Clausen: Lütfen güncellenmiş yanıtıma bakın. –

5

Sen kullanabileceği bir list comprehension: Bu yeni listesini üretir

arr = [i + 1 for i in arr] 

; Yukarıdaki örnekte sonucu aynı adaya geri döndürüyorum.

Listeye birden fazla başvurunuz varsa ve bunu yerinde değiştirmeniz gerekiyorsa (diğer başvurularda değişikliklere bakın), yeniden adlandırmak yerine listenin tüm dizinlerini güncelleştirmek için kimlik dilimine ([:]) atayın. isim:

arr[:] = [i + 1 for i in arr] 

bu ilk yeni bir liste nesnesi oluşturur ve Python sonra iki liste de aynı boyutta ve tekrar ikinci bir liste boşaltma önce sadece unsurları arasında kopyalamanız görecek kadar akıllı.

Hatta fazladan listesi oluşturma önlemek için bu durumda bir jeneratör ifade kullanabilirsiniz:

arr[:] = (i + 1 for i in arr) 

Bu yeni öğelere yer açmak için kenara özgün unsurlar taşır, ancak yeni Python liste nesnesi yaratılır bunun için. Bu, küçük daha fazla bellek etkin olmalıdır.

+0

Gerçekten çok pythonic! Bunu mikropythonda uyguladığımdan beri, yeni bir liste oluşturmak istemiyorum (zaten hafızamı doyuruyor!), Bu yüzden muhtemelen yerinde çözüme sadık kalacağım ... – Clausen

+2

@Clausen: bellekte kısıtlanmış envs o zaman bir jeneratör ifadesi kullanın. –

+2

@Clausen: Birden fazla cevabı faydalı bulduğuna sevindim! Ne yazık ki, 'kabul edilen' işaretini, buradaki cevaplardan yalnızca birine verebilirsiniz. En yararlı olduğunu düşündüğünüz birini seçin (seçim yapamıyorsanız, bir tane de seçmeyin, iyi de). –

3

Kullanım liste anlama:

arr = [x + 1 for x in arr] 
İlgili konular