First iteration of the For loop

Greetings pyc-sires and py-ladies, I would like to know if there is an elegant pythonic way to execute some function on the first iteration of the loop. The only opportunity I can think of is:

first = True for member in something.get(): if first: root.copy(member) first = False else: somewhereElse.copy(member) foo(member) 
+41
python algorithm iteration
Dec 18 '09 at 11:03
source share
12 answers

You have several design options for the Head-Tail template.

 seq= something.get() root.copy( seq[0] ) foo( seq[0] ) for member in seq[1:]: somewhereElse.copy(member) foo( member ) 

Or that

 seq_iter= iter( something.get() ) head = seq_iter.next() root.copy( head ) foo( head ) for member in seq_iter: somewhereElse.copy( member ) foo( member ) 

People whine that this is somehow not "DRY" because "the redundant code is foo (member)". This is a ridiculous demand. If so, then all functions can be used only once. What is the point of defining a function if you have only one link?

+27
Dec 18 '09 at 11:09
source share
— -

Something like this should work.

 for i, member in enumerate(something.get()): if i == 0: # Do thing # Code for everything 

However, I would highly recommend thinking about your code to see if you really need to do this because it is kind of dirty. It would be better to get an element that requires special processing in front, and then perform regular processing for everyone else in the loop.

The only reason I could not do this is to get a large list that you get from the generator expression (which you would not want to get from the front because it did not fit into the memory) or similar situations.

+51
Dec 18 '09 at 11:07
source share

What about:

 my_array = something.get() for member in my_array: if my_array.index(member) == 0: root.copy(member) else: somewhereElse.copy(member) foo(member) 

or maybe:

 for index, member in enumerate(something.get()): if index == 0: root.copy(member) else: somewhereElse.copy(member) foo(member) 

Documentation index method .

+8
Dec 20 '09 at 13:06
source share

I think this is pretty elegant, but perhaps too confusing for what he does ...

 from itertools import chain, repeat, izip for place, member in izip(chain([root], repeat(somewhereElse)), something.get()): place.copy(member) foo(member) 
+6
Dec 18 '09 at 11:55
source share

It works:

 for number, member in enumerate(something.get()): if not number: root.copy(member) else: somewhereElse.copy(member) foo(member) 

In most cases, I suggest just whatever[1:] over whatever[1:] and doing the root thing outside the loop; which is usually more readable. Of course, it depends on your use case.

+4
Dec 18 '09 at 11:07
source share

If something.get () iterates something, you can do it also as follows:

 root.copy(something.get()) for member in something.get(): # the rest of the loop 
+3
Dec 18 '09 at 11:08
source share

Here I can come up with a pythonic idiom that may look like "pertty". Although, most likely, I would use the form that you proposed, asking a question, just so that the code remains more obvious, although less elegant.

 def copy_iter(): yield root.copy while True: yield somewhereElse.copy for member, copy in zip(something.get(), copy_iter()): copy(member) foo(member) 

(sorry - the first one I posted before editing, the form did not work, I forgot to actually get an iterator for the copy object)

+3
Dec 18 '09 at 11:36
source share

How about using iter and consuming the first item?

Edit: Returning to the OP question, there is a general operation that you want to perform for all elements, and then one operation that you want to perform for the first element and the other for the rest.

If this is just one function call, I would just write it twice. It will not end the world. If it is more active, you can use the decorator to wrap your “first” function and “rest” with a general operation.

 def common(item): print "common (x**2):", item**2 def wrap_common(func): """Wraps `func` with a common operation""" def wrapped(item): func(item) common(item) return wrapped @wrap_common def first(item): """Performed on first item""" print "first:", item+2 @wrap_common def rest(item): """Performed on rest of items""" print "rest:", item+5 items = iter(range(5)) first(items.next()) for item in items: rest(item) 

Output:

 first: 2 common (x**2): 0 rest: 6 common (x**2): 1 rest: 7 common (x**2): 4 rest: 8 common (x**2): 9 rest: 9 common (x**2): 16 

or you can make a fragment:

 first(items[0]) for item in items[1:]: rest(item) 
+3
Dec 18 '09 at 12:37
source share

I think the first S.Lott solution is the best, but there is a different choice if you use quite recent python (> = 2.6, I think, since izip_longest is not yet available before this version), which allows you to do different things for the first element and sequential , and can be easily modified to perform separate operations for the 1st, 2nd, 3rd elements ... as well.

 from itertools import izip_longest seq = [1, 2, 3, 4, 5] def headfunc(value): # do something print "1st value: %s" % value def tailfunc(value): # do something else print "this is another value: %s" % value def foo(value): print "perform this at ANY iteration." for member, func in izip_longest(seq, [headfunc], fillvalue=tailfunc): func(member) foo(member) 
+2
Dec 18 '09 at 14:23
source share

You can not do root.copy(something.get()) before the loop?

EDIT: Sorry, I missed the second bit. But you get a general idea. Otherwise, list and check 0 ?

EDIT2: Well, got rid of the stupid second idea.

+1
Dec 18 '09 at 11:07
source share

I do not know Python, but I use an almost exact template of your example.
What I do also makes the if condition the most frequent, so usually check if( first == false )
What for? for long cycles, at first it will be true only once and all other times will be false, which means that in all cycles except the first, the program will check the status and go to the else part.
Checking that the first was false, there will be only one transition to the else part. I don’t know if this adds efficiency at all, but I still do it just to be at peace with my inner nerd.

PS: Yes, I know that when entering the if part, it must also jump over else to continue execution, so probably my way of doing this is useless, but it feels good .: D

+1
Dec 18 '09 at 12:50
source share

Your question is controversial. You say: “just do something in the first iteration”, when in fact you say something else in the first and subsequent iterations. Here is how I would try to do it:

 copyfn = root.copy for member in something.get(): copyfn(member) foo(member) copyfn = somewhereElse.copy 
0
Feb 20 '17 at 22:16
source share



All Articles