2017-02-22 20 views
32

list var ve başka bir liste (kavrama yoluyla) oluşturmak istiyorum.Anlamanın büyüklüğü nasıl sınırlanır?

a = [1, 2, 1, 2, 1, 2] 
b = [i for i in a if i == 1 and len(b) < 3] 

Traceback (most recent call last): 
    File "compr.py", line 2, in <module> 
    b = [i for i in a if i == 1 and len(b) < 3] 
    File "compr.py", line 2, in <listcomp> 
    b = [i for i in a if i == 1 and len(b) < 3] 
NameError: name 'b' is not defined 

b çünkü

ile henüz tanımlanmadı: Bu yeni liste

Aşağıdaki kod başarısız olur koşulu aracılığıyla, boyut olarak sınırlı istiyorum Anlama zamanı inşa edilmiştir.

yapı anda yeni listenin boyutunu sınırlamak için bir yolu var mı?

Not: bir karşı ulaşıldığında düzgün break ile for döngüye anlama kırabilir ama anlama kullanan bir mekanizma olup olmadığını bilmek istiyorum. Bu o 3 unsurları üretmek için gerektiğinden daha size daha fazla iş yapmayın sağlar

from itertools import islice 

filtered = (i for i in a if i == 1) 
b = list(islice(filtered, 3)) 

:

cevap

52

Sen yineleme sayısını sınırlamak için, sonra filtreleme yapmak islice() kullanmak için bir jeneratör ifade kullanabilirsiniz .

hiçbir nokta artık burada bir liste anlama kullanarak olmadığını

Not; Liste kavraması kesilemez, sonuna kadar yinelemek üzere kilitlenirsiniz.

+0

[1/i aralıkta (-5, 5)] 'patlak verir ve sonuna kadar iterasyon yapmaz. –

+12

@StefanPochmann: Bu bir istisna artar, bu * bir 'break' ifadesiyle aynı şey değildir. Sonuçta, hiç sonuç listeniz yok. –

+0

"break" ifadesini kastettiğiniz açık değildi, bu kelime daha genel bir şekilde anlaşılabilir. [Örneğin] (http://stackoverflow.com/a/38675546/1672429) uzun bir süre önce dediniz * "[' '' '' '' '' '' '' '”] döngüden çıkar. Her durumda, yineleme sona ermez. Ayrıca, bir liste sonucunun olmaması bile bir sorun olmak zorunda değildir. Reciprocals = [1/x for a] 'düşünün, bu makul bir kod olduğunu ve eğer bir 'sıfır' içeriyorsa o zaman bir 'ZeroDivisionError' isteyebilir ve bir liste istemez. –

6

@Martijn Pietersitertools.islice bu çözmek için en iyi yol olduğuna tamamen haklı. Ancak, ek bir (harici) kitaplığa sahip değilseniz, bu itertools ve uygulamalarının çoğunu (ve bazı ekleri) içeren iteration_utilities'u kullanabilirsiniz. Bu fonksiyonel programlama gibi en azından, bu biraz daha kolay yapabiliriz: Yalnızca süreç, gerekli görüldüğünde gibi birçok öğeler herhangi arayacak kadar böylece

>>> from iteration_utilities import Iterable 

>>> Iterable([1, 2, 1, 2, 1, 2]).filter((1).__eq__)[:2].as_list() 
[1, 1] 

>>> (Iterable([1, 2, 1, 2, 1, 2]) 
...   .filter((1).__eq__) # like "if item == 1" 
...   [:2]     # like "islice(iterable, 2)" 
...   .as_list())   # like "list(iterable)" 
[1, 1] 

iteration_utilities.Iterable sınıf içten jeneratörleri kullanan as_* (veya get_*) -Kullanılan.


Yasal Uyarı: Ben the iteration_utilities library yazarı değilim.

+1

Bu çok güzel bir kütüphanedir, teşekkürler (hala çok sayıda fonksiyona kavuşmak için dokümanlar okuyor) – WoJ

+1

İlk linki projenin ana sayfasına değiştirmenizi tavsiye ederim: http://iteration-utilities.readthedocs.io/ tr/son /? – jpmc26

3

sayacı istenen tamsayı (3 bu durumda) ulaştığında bir jeneratör için iterating durdurmak için itertools.takewhile bir sayaç oluşturmak için itertools.count kullanıp olabilir:

from itertools import count, takewhile 
c = count() 
b = list(takewhile(lambda x: next(c) < 3, (i for i in a if i == 1))) 

Ya bir yapı inşa benzer bir düşünce Jeneratörü sonlandırmak için StopIteration'u yükseltmek.Yani breaking the list comprehension ait orijinal fikrine alırsınız yakın, ama en iyi uygulama olarak tavsiye etmem:

c = count() 
b = list(i if next(c) < 3 else next(iter([])) for i in a if i == 1) 

Örnekler:

>>> a = [1,2,1,4,1,1,1,1] 

>>> c = count() 
>>> list(takewhile(lambda x: next(c) < 3, (i for i in a if i == 1))) 
[1, 1, 1] 

>>> c = count() 
>>> list(i if next(c) < 3 else next(iter([])) for i in a if i == 1) 
[1, 1, 1] 
+0

Diğer cevaplara göre bu avantaj nedir? – jpmc26

+0

@ jpmc26 Bu tam amaç için Martijn'in çözümünden daha iyi olduğunu sanmıyorum, ama daha genellenebilir çünkü jeneratörü sonlandırma koşulları sadece bir sayaç değil, bir şey olabilir. Ayrıca OP, özellikle bir liste kavraması hakkında sordu ve bu, –

+1

Fuarı için en uygun geçerli sözdizimidir. Teşekkürler. Bunu diğer cevaplardan sonra yayınladığınıza göre, cevabınıza esneklik avantajı hakkında bir şeyler yapmak isteyebilirsiniz. – jpmc26

-2

kullanım numaralandırmak:

b = [n for i,n in enumerate(a) if n==1 and i<3] 
+4

Bu sadece yanlıştır. İlk olarak, bu 'a' nin ilk 3 maddesi hariç her şeyi (“b” yi sınırlamak istenen soru) hariç tutmaz ve tüm yinelenebilirliği işleyecektir. Üçüncü maddeyi bulduktan sonra durmayacak. Sadece bundan sonra her şeyi atar (ancak n == 1 ve i <3' kontrol eder). – MSeifert

İlgili konular