Better way to swap elements in a list?

后端 未结 14 1268
臣服心动
臣服心动 2020-12-23 13:32

I have a bunch of lists that look like this one:

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

I want to swap elements as follows:

fi         


        
14条回答
  •  甜味超标
    2020-12-23 14:23

    A benchmark between top answers:

    Python 2.7:

    ('inp1 ->', 15.302665948867798) # NPE's answer 
    ('inp2a ->', 10.626379013061523) # alecxe's answer with chain
    ('inp2b ->', 9.739919185638428) # alecxe's answer with chain.from_iterable
    ('inp3 ->', 2.6654279232025146) # Anzel's answer
    

    Python 3.4:

    inp1 -> 7.913498195000102
    inp2a -> 9.680125927000518
    inp2b -> 4.728151862000232
    inp3 -> 3.1804273489997286
    

    If you are curious about the different performances between python 2 and 3, here are the reasons:

    As you can see @NPE's answer (inp1) performs very better in python3.4, the reason is that in python3.X range() is a smart object and doesn't preserve all the items between that range in memory like a list.

    In many ways the object returned by range() behaves as if it is a list, but in fact it isn’t. It is an object which returns the successive items of the desired sequence when you iterate over it, but it doesn’t really make the list, thus saving space.

    And that's why in python 3 it doesn't return a list while you slice the range object.

    # python2.7
    >>> range(10)[2:5]
    [2, 3, 4]
    # python 3.X
    >>> range(10)[2:5]
    range(2, 5)
    

    The second significant change is performance accretion of the third approach (inp3). As you can see the difference between it and the last solution has decreased to ~2sec (from ~7sec). The reason is because of the zip() function which in python3.X it returns an iterator which produces the items on demand. And since the chain.from_iterable() needs to iterate over the items once again it's completely redundant to do it before that too (what that zip does in python 2).

    Code:

    from timeit import timeit
    
    
    inp1 = """
    [l[i^1] for i in range(len(l))]
       """
    inp2a = """
    list(chain(*zip(l[1::2], l[0::2])))
    """
    inp2b = """
    list(chain.from_iterable(zip(l[1::2], l[0::2])))
    """
    inp3 = """
    l[::2], l[1::2] = l[1::2], l[::2]
    """
    
    lst = list(range(100000))
    print('inp1 ->', timeit(stmt=inp1,
                            number=1000,
                            setup="l={}".format(lst)))
    print('inp2a ->', timeit(stmt=inp2a,
                            number=1000,
                            setup="l={}; from itertools import chain".format(lst)))
    print('inp2b ->', timeit(stmt=inp2b,
                            number=1000,
                            setup="l={}; from itertools import chain".format(lst)))
    print('inp3 ->', timeit(stmt=inp3,
                            number=1000,
                            setup="l={}".format(lst)))
    

提交回复
热议问题