23

list_a2つのリストを連結する最も効率的な方法は何ですかlist_b

  • list_blist_aアイテムはアイテムの前に配置する必要があります
  • 結果はに配置する必要がありますlist_a

私は4つの可能性を念頭に置いています:

# 1
list_a = list_b + list_a

# 2
for item in list_b:
    list_a.insert(0, item)

# 3
for item in self.list_a:
    list_b.append(item)
list_a = list_b

# 4
list_a[0:0] = list_b

ありがとう!

4

6 に答える 6

32

これは、リストの長さが長くなるにつれて、BigYellowCactusの回答で使用されるタイミングがどのように変化するかを示すグラフです。縦軸は、usecで両方のリストを初期化し、一方を他方の前に挿入するのに必要な時間です。横軸はリスト内のアイテム数です。

可能性の漸近的振る舞い

t1

list_a = list_b + list_a

t2

for item in list_b:
    list_a.insert(0, item)

t3

for item in list_a:
    list_b.append(item)
list_a = list_b

t4

list_a[0:0] = list_b
于 2012-08-23T09:34:36.603 に答える
8

とすれば

list_a = list_b + list_a

list_a目的に応じて機能するため、すべてのデータを格納するためにオブジェクト自体は実際には必要ありません。必要なのは、オブジェクトを呼び出すlist_aだけです(つまり、他の変数を持っていないか、気にしません)。その周りに浮かんでいると、同じリストを参照する可能性があります)。 list_a

それが正確にリストであることを気にせず、反復可能であることだけを気にする場合は、次を使用できますitertools.chain

list_a = itertools.chain(list_b, list_a)

リストのことを気にする場合chainは、リストのように動作するものと同様のタイプのものを作成できます。たとえば、次のようになります。

class ListChain(list):
    def __init__(self, *lists):
        self._lists = lists

    def __iter__(self):
        return itertools.chain.from_iterable(self._lists)

    def __len__(self):
        return sum(len(l) for l in self._lists)

    def append(self, item):
        self._lists[-1].append(item)

    def extend(self, iterable):
        self._lists.append(list(iterable))

    def __getitem__(self, item):
       for l in self._lists:
           if item < len(l):
              return l[item]
           item -= len(l)
       else:
          raise IndexError

など。これがすべての場合に機能するには、多くの労力(おそらくその価値以上)が必要になります。たとえば、スライスや負のインデックスの処理が頭に浮かびます。ただし、非常に単純なケースの場合、このアプローチにより、リストの内容を大量にコピーすることを回避できます。

于 2012-08-23T10:12:49.453 に答える
6

list_bをスライスに割り当てることができます。スライスはたまたま空ですが、list_aの先頭にあります。

list_a[0:0] = list_b

これは、任意の位置でリストを別のリストに挿入するための最速の方法です。

于 2012-08-23T09:00:33.967 に答える
5

これを試して:

list_a[0:0] = list_b
于 2012-08-23T08:59:01.977 に答える
4

なぜだけではないのtimeitですか?

import timeit

create_data = """\
list_a = range(10)
list_b = range(10)
"""

t1 = timeit.Timer(stmt=create_data + """\
list_a = list_b + list_a
""")

t2 = timeit.Timer(create_data + """\
for item in list_b:
    list_a.insert(0, item)
""")

t3 = timeit.Timer(create_data + """\
for item in list_a:
    list_b.append(item)
list_a = list_b
""")

t4 = timeit.Timer(create_data + """\
list_a[0:0] = list_b
""")

for i, t in enumerate([t1,t2,t3,t4]):
    print i, "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

結果:

0 0.73 usec / pass
1 2.79 usec / pass
2 1.66 usec / pass
3 0.77 usec / pass

于 2012-08-23T09:03:06.760 に答える
4

ここに画像の説明を入力してください

itertools.chainジェネレーターを作成するだけなので、リストの代わりにジェネレーターを使用する必要がない場合は、生成するのに一定の時間がかかりますが、各要素にアクセスするときにコストを支払います。それ以外の場合list_a[0:0] = list_bは、約6倍高速ですlist_a = list_b + list_a

私はそれlist_a = list_b + list_aが最も読みやすい選択だと思います、そしてそれはすでにかなり速いです。

append()ループでの使用についておっしゃった2つの方法forは非常に遅いので、わざわざそれらを含めませんでした。


[Clang 11.0.0 (clang-1100.0.33.8)] on darwin次のコードを使用して、16GBの2133MHzLPDDR3RAMを搭載した1.6GHzデュアルコアIntelCorei5でPython3.7.5を実行しました。

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()
于 2019-11-17T07:43:02.943 に答える