Efficient way to rotate a list in python

后端 未结 26 1132
一生所求
一生所求 2020-11-22 03:14

What is the most efficient way to rotate a list in python? Right now I have something like this:

>>> def rotate(l, n):
...     return l[n:] + l[:n]         


        
相关标签:
26条回答
  • 2020-11-22 03:37

    I also got interested in this and compared some of the suggested solutions with perfplot (a small project of mine).

    It turns out that

    for _ in range(n):
        data.append(data.pop(0))
    

    is by far the fastest method for small shifts n.

    For larger n,

    data[n:] + data[:n]
    

    isn't bad.

    Essentially, perfplot performs the shift for increasing large arrays and measures the time. Here are the results:

    shift = 1:

    shift = 100:


    Code to reproduce the plot:

    import numpy
    import perfplot
    import collections
    
    
    shift = 100
    
    
    def list_append(data):
        return data[shift:] + data[:shift]
    
    
    def shift_concatenate(data):
        return numpy.concatenate([data[shift:], data[:shift]])
    
    
    def roll(data):
        return numpy.roll(data, -shift)
    
    
    def collections_deque(data):
        items = collections.deque(data)
        items.rotate(-shift)
        return items
    
    
    def pop_append(data):
        for _ in range(shift):
            data.append(data.pop(0))
        return data
    
    
    perfplot.save(
        "shift100.png",
        setup=lambda n: numpy.random.rand(n).tolist(),
        kernels=[list_append, roll, shift_concatenate, collections_deque, pop_append],
        n_range=[2 ** k for k in range(7, 20)],
        xlabel="len(data)",
    )
    
    0 讨论(0)
  • 2020-11-22 03:37

    I have similar thing. For example, to shift by two...

    def Shift(*args):
        return args[len(args)-2:]+args[:len(args)-2]
    
    0 讨论(0)
  • 2020-11-22 03:37
    def solution(A, K):
        if len(A) == 0:
            return A
    
        K = K % len(A)
    
        return A[-K:] + A[:-K]
    
    # use case
    A = [1, 2, 3, 4, 5, 6]
    K = 3
    print(solution(A, K))
    

    For example, given

    A = [3, 8, 9, 7, 6]
    K = 3
    

    the function should return [9, 7, 6, 3, 8]. Three rotations were made:

    [3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7]
    [6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9]
    [7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8]
    

    For another example, given

    A = [0, 0, 0]
    K = 1
    

    the function should return [0, 0, 0]

    Given

    A = [1, 2, 3, 4]
    K = 4
    

    the function should return [1, 2, 3, 4]

    0 讨论(0)
  • 2020-11-22 03:37

    What is the use case? Often, we don't actually need a fully shifted array --we just need to access a handful of elements in the shifted array.

    Getting Python slices is runtime O(k) where k is the slice, so a sliced rotation is runtime N. The deque rotation command is also O(k). Can we do better?

    Consider an array that is extremely large (let's say, so large it would be computationally slow to slice it). An alternative solution would be to leave the original array alone and simply calculate the index of the item that would have existed in our desired index after a shift of some kind.

    Accessing a shifted element thus becomes O(1).

    def get_shifted_element(original_list, shift_to_left, index_in_shifted):
        # back calculate the original index by reversing the left shift
        idx_original = (index_in_shifted + shift_to_left) % len(original_list)
        return original_list[idx_original]
    
    my_list = [1, 2, 3, 4, 5]
    
    print get_shifted_element(my_list, 1, 2) ----> outputs 4
    
    print get_shifted_element(my_list, -2, 3) -----> outputs 2 
    
    0 讨论(0)
  • 2020-11-22 03:39

    Numpy can do this using the roll command:

    >>> import numpy
    >>> a=numpy.arange(1,10) #Generate some data
    >>> numpy.roll(a,1)
    array([9, 1, 2, 3, 4, 5, 6, 7, 8])
    >>> numpy.roll(a,-1)
    array([2, 3, 4, 5, 6, 7, 8, 9, 1])
    >>> numpy.roll(a,5)
    array([5, 6, 7, 8, 9, 1, 2, 3, 4])
    >>> numpy.roll(a,9)
    array([1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    0 讨论(0)
  • 2020-11-22 03:42

    What about just using pop(0)?

    list.pop([i])

    Remove the item at the given position in the list, and return it. If no index is specified, a.pop() removes and returns the last item in the list. (The square brackets around the i in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the Python Library Reference.)

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