python list concatenation efficiency

前端 未结 6 1390
陌清茗
陌清茗 2020-12-16 13:07

What is the most efficient way to concatenate two lists list_a and list_b when:

  • list_b items have to be placed before
6条回答
  •  感动是毒
    2020-12-16 13:28

    itertools.chain just makes a generator, so if you can get away with using a generator instead of a list, it's constant time to generate but you pay the cost when you access each element. Otherwise list_a[0:0] = list_b is about 6 times faster than list_a = list_b + list_a

    I think that list_a = list_b + list_a is the most readable choice and it's already pretty fast.

    The two methods that you mentioned that use append() in a for loop are unusably slow so I didn't bother including them.


    Ran with Python 3.7.5 [Clang 11.0.0 (clang-1100.0.33.8)] on darwin on a 1.6 GHz Dual-Core Intel Core i5 with 16 GB of 2133 MHz LPDDR3 RAM using the following code:

    from timeit import timeit
    import random
    import matplotlib.pyplot as plt
    
    num_data_points = 1000
    step = 10
    methods = [
        # ordered from slowest to fastest to make the key easier to read
        # """for item in list_a: list_b.append(item); list_a = list_b""",
        # """for item in list_b: list_a.insert(0, item)""",
        # "list_a = list(itertools.chain(list_b, list_a))",
        "list_a = list_b + list_a",
        "list_a[0:0] = list_b",
        "list_a = itertools.chain(list_b, list_a)",
    ]
    
    x = list(range(0, num_data_points * step, step))
    y = [[] for _ in methods]
    for i in x:
        list_a = list(range(i))
        list_b = list(range(i))
        random.shuffle(list_a)
        random.shuffle(list_b)
        setup = f"list_a = {list_a}; list_b = {list_b}"
        for method_index, method in enumerate(methods):
            y[method_index].append(timeit(method, setup=setup, number=30))
        print(i, "out of", num_data_points * step)
    
    ax = plt.axes()
    for method_index, method in enumerate(methods):
        ax.plot(x, y[method_index], label=method)
    ax.set(xlabel="number of elements in both lists", ylabel="time (s) (lower is better)")
    ax.legend()
    plt.show()
    

提交回复
热议问题