python - What's an elegant way for one loop iteration to affect another? -
i needed process config file now. because of way generated, contains lines this:
---(more 15%)---
the first step strip these unwanted lines out. slight twist, each of these lines followed blank line, want strip. created quick python script this:
skip_next = false line in sys.stdin: if skip_next: skip_next = false continue if line.startswith('---(more'): skip_next = true continue print line,
now, works, it's more hacky i'd hoped. difficulty when looping through lines, want content of 1 line affect subsequent line. hence question: what's elegant way 1 loop iteration affect another?
another way itertools.tee
, allows split iterator two. can advance 1 iterator 1 step, putting 1 iterator 1 line ahead of other. can zip 2 iterators , @ both previous line , current line @ each step of for
loop (i use izip_longest
doesn't drop last line):
from itertools import tee, izip_longest in1, in2 = tee(sys.stdin, 2) next(in2) line, prevline in izip_longest(in1, in2, fillvalue=''): if line.startswith('---(more') or prevline.startswith('---(more'): continue print line
this done equivalent generator expression:
from itertools import tee, izip_longest in1, in2 = tee(sys.stdin, 2) next(in2) pairs = izip_longest(in1, in2, fillvalue='') res = (line line, prevline in pairs if not line.startswith('---(more') , not prevline.startswith('---(more')) line in res: print line
or use filter
, allows drop iterator items when condition not true.
from itertools import tee, izip_longest in1, in2 = tee(sys.stdin, 2) next(in2) pairs = izip_longest(in1, in2, fillvalue='') cond = lambda pair: not pair[0].startswith('---(more') , not pair[1].startswith('---(more') res = filter(cond, pairs) line in res: print line
if willing go outside python standard library, toolz
package makes easier. provides sliding_window
function, allows split iterator such a b c d e f
(a,b), (b,c), (c,d), (d,e), (e,f)
. same thing tee
approach above, combined 3 lines one:
from toolz.itertoolz import sliding_window line, prevline in sliding_wind(2, sys.stdin): if line.startswith('---(more') or prevline.startswith('---(more'): continue print line
you additionally use remove
, opposite of filter
, drop items without needing for
loop:
from tools.itertoolz import sliding_window, remove pairs = sliding_window(2, sys.stdin) cond = lambda x: x[0].startswith('---(more') or x[1].startswith('---(more') res = remove(cond, pairs) line in res: print line
Comments
Post a Comment