Yineleme bir dize hatları
Çok satırlı bir dize böyle tanımlıyorum:
foo = """
this is
a multi-line string.
"""
Bu dize yazıyorum bir çözümleyici için test giriş olarak bizi kullandı. Parser-function file
-nesne girdi olarak alır ve yineler. next()
Bu yöntem, doğrudan satır atlamak için çağrı da, gerçekten girdi, bir iterable gibi bir yineleyici.
file
-nesne gibi dize tek tek satırları üzerinde yineleme metin dosyası hatları bir yineleyici ihtiyacım var. Elbette bu böyle olabilir:
lineiterator = iter(foo.splitlines())
Bunun daha kestirme bir yolu var mı? Bu senaryoda dize bir kez bölme için geçiş ve sonra tekrar çözümleyici tarafından. Test-case, ip çok kısa olduğu için, sadece meraktan soruyorum benim için önemli değil. Python çok yararlı ve verimli built-ins böyle şeyler için vardır, ama bu ihtiyaca uygun bir şey bulamadım.
CEVAP
Burada üç ihtimal var:
foo = """
this is
a multi-line string.
"""
def f1(foo=foo): return iter(foo.splitlines())
def f2(foo=foo):
retval = ''
for char in foo:
retval = char if not char == '\n' else ''
if char == '\n':
yield retval
retval = ''
if retval:
yield retval
def f3(foo=foo):
prevnl = -1
while True:
nextnl = foo.find('\n', prevnl 1)
if nextnl < 0: break
yield foo[prevnl 1:nextnl]
prevnl = nextnl
if __name__ == '__main__':
for f in f1, f2, f3:
print list(f())
Ana senaryo olarak çalışan bu üç fonksiyon eşdeğer olduğunu doğruladı. timeit
(ve daha kesin ölçüm için önemli dizeleri almak için foo
* 100
):
$ python -mtimeit -s'import asp' 'list(asp.f3())'
1000 loops, best of 3: 370 usec per loop
$ python -mtimeit -s'import asp' 'list(asp.f2())'
1000 loops, best of 3: 1.36 msec per loop
$ python -mtimeit -s'import asp' 'list(asp.f1())'
10000 loops, best of 3: 61.5 usec per loop
Bu kullanımına, sadece inşa geçiş sağlamak için list()
çağrı ihtiyacımız var unutmayın.
ALÇAK, saf uygulama çok daha hızlı değil hatta komik: 6 kat daha hızlı, daha denemem ile find
aramalar, devre 4 kat daha hızlı daha alt düzey bir yaklaşım.
Ders korur: ölçüm her zaman iyi bir şey olmalı ama doğru); string yöntemleri gibi splitlines
uygulandığını çok hızlı yol; koyarak dizeleri birlikte programlama bir çok düşük seviye (esp. çok küçük parçalar) =
döngüler oldukça yavaş olabilir.
Edit: @Jacob önerisi, biraz diğerleri gibi aynı sonuçları (bir satır boşluk tutulur) değiştirilmiş, yani: eklendi
from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl != '':
yield nl.strip('\n')
else:
raise StopIteration
Ölçüm verir:
$ python -mtimeit -s'import asp' 'list(asp.f4())'
1000 loops, best of 3: 406 usec per loop
oldukça iyi olarak .find
dayalı bir yaklaşım hala, değer tutmak zihin, çünkü bu belki daha az eğilimli küçük devre dışı-tarafından bir hata (herhangi bir döngü nerede görüyorsunuz tekrarı 1 ve -1, benim gibi f3
yukarıda, gereken otomatik olarak tetikten tek kuşkular ve gereken birçok döngüler eksikliği bu tür uygulamalar olmalı ... ama sanırım benim kod da doğru yaşımdan beri mümkün için onay çıktı diğer fonksiyonlar').
Ama split merkezli kurallar yaklaşım.
f4
tarzı olurdu belki daha iyi: kenara bir:
from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl == '': break
yield nl.strip('\n')
en azından biraz daha az ayrıntılı. İhtiyaç striptiz izleyen \n
s ne yazık ki yasaklar daha net ve daha hızlı değiştirme while
döngü ile return iter(stri)
(iter
bölüm rakamın gereksiz modern sürümleri Python, inanıyorum beri 2.3 veya 2.4, ama aynı zamanda zararsız). Denemeye değer belki de
return itertools.imap(lambda s: s.strip('\n'), stri)
ya da çeşitleri -- ama çok fazla strip
temel, en basit ve en hızlı bir wrt teorik bir çalışma olduğu için burada kesiyorum.
YAML, birden çok hatları üzerinden bir...
Bir Liste dönüştürmek için nasıl<Di...
Yineleme PHP bir dize her satır üzerin...
Nasıl bir Dize bir karakter yineleme s...
Neden küçük bir liste daha küçük bir d...