“For” loop first iteration

前端 未结 13 2342
渐次进展
渐次进展 2020-12-04 15:17

I would like to inquire if there is an elegant pythonic way of executing some function on the first loop iteration. The only possibility I can think of is:

f         


        
相关标签:
13条回答
  • 2020-12-04 15:46

    I think the first S.Lott solution is the best, but there's another choice if you're using a pretty recent python (>= 2.6 I think, since izip_longest doesn't seem available before that version) that lets doing different things for the first element and successive one, and can be easily modified to do distinct operations for 1st, 2nd, 3rd element... 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)
    
    0 讨论(0)
  • 2020-12-04 15:49

    You have several choices for the Head-Tail design pattern.

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

    Or this

    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 foo(member)" code. That's a ridiculous claim. If that was true then all functions could only be used once. What's the point of defining a function if you can only have one reference?

    0 讨论(0)
  • 2020-12-04 15:50

    how 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 of index-method.

    0 讨论(0)
  • 2020-12-04 15:52

    Here, I could come with a Pythonic idiom that can look "pertty". Although, most likely I'd use the form you suggested in asking the question, just for the code to remain more obvious, though 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 I posted, before editing, form would not work, I had forgotten to actually get an iterator for the 'copy' object)

    0 讨论(0)
  • 2020-12-04 15:53

    How about using iter, and consuming the first element?

    Edit: Going back on the OP's question, there is a common operation that you want to perform on all elements, and then one operation you want to perform on the first element, and another on the rest.

    If it's just a single function call, I'd say just write it twice. It won't end the world. If it's more involved, you can use a decorator to wrap your "first" function and "rest" function with a common 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 could do a slice:

    first(items[0])
    for item in items[1:]:
        rest(item)
    
    0 讨论(0)
  • 2020-12-04 15:54

    I don't know Python, but I use almost the exact pattern of your example.
    What I do also is making the if condition the most frequent, so usually check for if( first == false )
    Why? for long loops, first will be true only one time and will be false all the other times, meaning that in all loops but the first, the program will check for the condition and jump to the else part.
    By checking for first being false, there will be only one jump to the else part. I don't really know if this adds efficiency at all, but I do it anyway, just to be in peace with my inner nerd.

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

    0 讨论(0)
提交回复
热议问题