looping over more than one list

T

Tim Chase

def lowest(s1,s2):
s = ""
for i in xrange(len(s1)):
s += lowerChar(s1,s2)
return s

this seems unpythonic, compared to something like:

def lowest(s1,s2):
s = ""
for c1,c2 in s1,s2:
s += lowerChar(c1,c2)
return s


If I understand correctly, something like

for c1,c2 in zip(s1,s2):

is what you're looking for. It will gracefully stop when it
reaches the end of the shortest input. (in your indexed
example above, if s2 is shorter than s1, it will likely
throw an out-of-bounds exception)

For your example, I'd use

def lowest(s1,s2):
return ''.join([lowerChar(c1,c2) for c1,c2 in zip(s1,s2)])

which seems to do what you describe (I understand that
appending to strings is an inefficient operation and is
better done with a join like this)

-tkc
 
I

Iain King

When I loop over one list I use:

for item in items:
print item

but often I want to loop through two lists at once, and I've been doing
this like I would in any other language - creating an index counter and
incrementing it.
For example, (completely arbitrary), I have two strings of the same
length, and I want to return a string which, at each character
position, has the letter closest to 'A' from each of the original
strings:

def lowest(s1,s2):
s = ""
for i in xrange(len(s1)):
s += lowerChar(s1,s2)
return s

this seems unpythonic, compared to something like:

def lowest(s1,s2):
s = ""
for c1,c2 in s1,s2:
s += lowerChar(c1,c2)
return s

this doesn't work - s1,s2 becomes a tuple. Is there a way to do this
that I'm missing? I don't see it in the docs.

This works:

def lowest(s1,s2):
s = ""
for c1,c2 in [x for x in zip(s1,s2)]:
s += lowerChar(c1,c2)
return s

but it's hardly any more elegant than using a loop counter, and I'm
guessing it's performance is a lot worse - I assume that the zip
operation is extra work?

Iain
 
D

Dylan Moreland

def lowest(s1,s2):
s = ""
for c1,c2 in [x for x in zip(s1,s2)]:
s += lowerChar(c1,c2)
return s

but it's hardly any more elegant than using a loop counter, and I'm
guessing it's performance is a lot worse - I assume that the zip
operation is extra work?

Iain

Always look in itertools for stuff like this:

http://docs.python.org/lib/itertools-functions.html#l2h-1392

for c1, c2 in itertools.izip(s1, s2):
...

I haven't profiled it, but it makes sense that this would be fast.
 
E

EleSSaR^

Iain King si è profuso/a a scrivere su comp.lang.python tutte queste
elucubrazioni:

[cut]

I think you should take a look at the zip() function.

You can use for with it like this:

for elem1, elem2, elem3 in zip(list1, list2, list3):
.....



--
Alan Franzoni <[email protected]>
-
Togli .xyz dalla mia email per contattarmi.
Rremove .xyz from my address in order to contact me.
-
GPG Key Fingerprint:
5C77 9DC3 BD5B 3A28 E7BC 921A 0255 42AA FE06 8F3E
 
A

Alex Martelli

Iain King said:
This works:

def lowest(s1,s2):
s = ""
for c1,c2 in [x for x in zip(s1,s2)]:
s += lowerChar(c1,c2)
return s

but it's hardly any more elegant than using a loop counter, and I'm
guessing it's performance is a lot worse - I assume that the zip
operation is extra work?

1. [x for x in whateverlist] just doesn't make sense! If you need a
copy of whateverlist, just use list(whateverlist). When you don't need
a copy, like here, just use whateverlist. I.e., loop this way:

for c1, c2 in zip(s1, s2):

2. performance is destroyed by building up a big list with a += of many
small pieces. Use cStringIO (some people prefer it for style reasons)
or (what most people do) ''.join a list where you've accumulated the
results.

3. this case is ideal for build-in function map.

The body of the function could be just one statement:

return ''.join(map(lowerChar, s1, s2))

This probably gives best performance.

Also consider a genexp and avoiding the unpacking/repacking a la:

return ''.join(lowerChar(*cs) for cs in zip(s1, s2))

or better:

import itertools

and then

return ''.join(lowerChar(*cs) for cs in itertools.izip(s1, s2))

or

return ''.join(itertools.imap(lowerChar, s1, s2))

If you care about performance, use module timeit from the standard
library to measure cases of interest.

If you don't (not especially) then the first solution looks neat,
elegant, readable, and concise.

But never build up substantial strings with a loop of += of small
strings: that's O(N squared) and will MAKE you care about performance
even where you otherwise wouldn't!-)


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top