By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,995 Members | 1,073 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,995 IT Pros & Developers. It's quick & easy.

Enumerate question: Inner looping like in Perl

P: n/a
Hi,

I have Perl code looping thru lines in the file:

line: while (<INFILE>) {
...
$_ = do something
...
if (/#START/) {
# Start inner loop
while (<INFILE>) {
if (/#END/) {
next line;
}
}
}
if (/#BLAH1/) {
$_ = do something
}
if (/#BLAH2/) {
$_ = do something
}
}
I decided to use enumerate() in my Python version
since current line must be modified (the $_ = idiom in Perl)

---code starts---

fh = codecs.open(f_path, "rU", "utf-8")
contents = fh.readlines()
fh.close()

# Precompile regular expressions (speed hack?)
findSTART = r'#START'
matcherSTART = re.compile(findSTART, re.UNICODE)
findEND = r'#END'
matcherEND = re.compile(findEND, re.UNICODE)
for i, row in enumerate(contents):
row[i] = something
if matcherSTART.search(row):
"Oops! how to advance 'i' and 'row' untill:
if matcherEND.search(row):
continue

---code ends---

I could create extra parameter to store the state of the loop like:

foundSTART = False
for i, row in enumerate(contents):
if foundSTART:
if not matcherEND.search(row):
continue
else:
foundSTART = False
else:
if matcherSTART.search(row):
foundSTART = True
if foundBLAH1:
row[i] = something
if foundBLAH2:
row[i] = something

but is this it really more maintainable code?

Is there enumerate() hack that I am missing or
should I go back to idiom?:

for i in range(len(contents)):
if matcherSTART.search(row[i]):
while not matcherEND.search(row[i]):
i = i + 1
continue
-pekka-
Jul 18 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Pekka Niiranen <pe************@wlanmail.com> wrote:
...
for i, row in enumerate(contents):
row[i] = something
if matcherSTART.search(row):
"Oops! how to advance 'i' and 'row' untill:
if matcherEND.search(row):
continue
You take an explicit iterator and call its .next() method (or
equivalently use an inner for on the iterator, if that is sufficient, as
it appears to be in this case -- see later).
Is there enumerate() hack that I am missing or
should I go back to idiom?:

for i in range(len(contents)):
if matcherSTART.search(row[i]):
while not matcherEND.search(row[i]):
i = i + 1
continue


this 'idiom' won't do what you want; i is set again to the very next
value, ignoring all modifications in the loop's body, when execution
gets back to the loop's header.

Here, probably, is what you want:

looper = iter(enumerate(contents))
for i, row in looper:
row[i] = something
if matcherSTART.search(row):
for i, row in looper:
if matcherEND.search(row):
break
Alex
Jul 18 '05 #2

P: n/a
Pekka Niiranen <pekka.niiranen <at> wlanmail.com> writes:
for i, row in enumerate(contents):
row[i] = something
if matcherSTART.search(row):
"Oops! how to advance 'i' and 'row' untill:
if matcherEND.search(row):
continue


Usually I would do this kind of thing by just keeping the iterator around. The
example below has two loops, an outer and an inner, and both iterate over the
same enumeration. (I've used 'char ==' instead of regular expressions to make
the output a little clearer, but hopefully you can do the translation back to
regexps for your code.)
contents = list('abcdefg')
itr = enumerate(contents)
for i, char in itr: .... print 'outer', i, char
.... contents[i] = char.upper()
.... if char == 'd':
.... for i, char in itr:
.... print 'inner', i, char
.... if char == 'f':
.... break
....
outer 0 a
outer 1 b
outer 2 c
outer 3 d
inner 4 e
inner 5 f
outer 6 g contents

['A', 'B', 'C', 'D', 'e', 'f', 'G']

Steve

Jul 18 '05 #3

P: n/a
Steven Bethard wrote:
Pekka Niiranen <pekka.niiranen <at> wlanmail.com> writes:

for i, row in enumerate(contents):
row[i] = something
if matcherSTART.search(row):
"Oops! how to advance 'i' and 'row' untill:
if matcherEND.search(row):
continue

Usually I would do this kind of thing by just keeping the iterator around. The
example below has two loops, an outer and an inner, and both iterate over the
same enumeration. (I've used 'char ==' instead of regular expressions to make
the output a little clearer, but hopefully you can do the translation back to
regexps for your code.)

contents = list('abcdefg')
itr = enumerate(contents)
for i, char in itr:
... print 'outer', i, char
... contents[i] = char.upper()
... if char == 'd':
... for i, char in itr:
... print 'inner', i, char
... if char == 'f':
... break
...

Thanks, I decided to catch logical error of not
finding "f" -letter at all with:
def myiter(contents): .... itr = enumerate(contents)
.... for i, char in itr:
.... print 'outer', i, char
.... if char == 'd':
.... try:
.... for i, char in itr:
.... print 'inner', i, char
.... if char == 'f':
.... break
.... except StopIteration:
.... print "f not found"
.... contents = list('abcdeg')
myiter(contents)
outer 0 a
outer 1 b
outer 2 c
outer 3 d
inner 4 e
inner 5 g

Not working: Iter() takes care of its own exceptions?
This recurring feeling that writing REALLY correct programs in Python
is not easier than in lower level languages... :(

-pekka-


outer 0 a
outer 1 b
outer 2 c
outer 3 d
inner 4 e
inner 5 f
outer 6 g
contents


['A', 'B', 'C', 'D', 'e', 'f', 'G']

Steve

Jul 18 '05 #4

P: n/a
On Sun, 31 Oct 2004 12:28:47 +0200, Pekka Niiranen <pe************@wlanmail.com> wrote:
Steven Bethard wrote:
Pekka Niiranen <pekka.niiranen <at> wlanmail.com> writes:

for i, row in enumerate(contents):
row[i] = something
if matcherSTART.search(row):
"Oops! how to advance 'i' and 'row' untill:
if matcherEND.search(row):
continue

Usually I would do this kind of thing by just keeping the iterator around. The
example below has two loops, an outer and an inner, and both iterate over the
same enumeration. (I've used 'char ==' instead of regular expressions to make
the output a little clearer, but hopefully you can do the translation back to
regexps for your code.)

>contents = list('abcdefg')
>itr = enumerate(contents)
>for i, char in itr:


... print 'outer', i, char
... contents[i] = char.upper()
... if char == 'd':
... for i, char in itr:
... print 'inner', i, char
... if char == 'f':
... break
...

Thanks, I decided to catch logical error of not
finding "f" -letter at all with:
def myiter(contents):... itr = enumerate(contents)
... for i, char in itr:
... print 'outer', i, char
... if char == 'd':

#XXX# >... #try:... for i, char in itr:
... print 'inner', i, char
... if char == 'f':
... break else:
print "f not found"
#XXX >... #except StopIteration:
#XXX >... # print "f not found"... contents = list('abcdeg')
myiter(contents)outer 0 a
outer 1 b
outer 2 c
outer 3 d
inner 4 e
inner 5 g

Not working: Iter() takes care of its own exceptions?
This recurring feeling that writing REALLY correct programs in Python
is not easier than in lower level languages... :(

-pekka-


outer 0 a
outer 1 b
outer 2 c
outer 3 d
inner 4 e
inner 5 f
outer 6 g
>contents


['A', 'B', 'C', 'D', 'e', 'f', 'G']

Steve

Try above (untested), noting:
itr = enumerate('abcdef')
for i,c in itr: ... print i,c
... if c=='d': break
... else:
... print 'first else'
...
0 a
1 b
2 c
3 d for i,c in itr:

... print i,c
... if c=='z': break
... else:
... print '2nd else'
...
4 e
5 f
2nd else

Regards,
Bengt Richter
Jul 18 '05 #5

P: n/a
Pekka Niiranen <pe************@wlanmail.com> wrote:
...
... try:
... for i, char in itr:
... print 'inner', i, char
... if char == 'f':
... break
... except StopIteration:
... print "f not found" ... Not working: Iter() takes care of its own exceptions?
Nope. Rather, the 'for' statement does not propagate the StopIteration
exception that terminates it -- such a propagation would be extremely
disruptive of 99% of Python's programs, and I'm astonished that you
expected it!

What you want is, I believe, among the Tutorial's examples...:

for i, ch in itr:
print 'inner', i, ch
if ch == 'f': break
else:
print 'f not found'

That's what the 'else' clause in a 'for' statement is for: it triggers
when the loop terminates normally (as opposed to ending with a break or
return or by propagating an exception). The ability to deal with a "not
found" case, where the "found" cases exit by break, is the main use case
of this 'else' clause.
This recurring feeling that writing REALLY correct programs in Python
is not easier than in lower level languages... :(


I think that you can get all the info about Python you need for the
purpose (and then some) from "Python in a Nutshell", but of course I'm
biased...;-)
Alex
Jul 18 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.