リストから値のすべての出現を削除しますか?


378

Python remove()では、リスト内の最初のvalueを削除します。

リストから値のすべての出現を削除するにはどうすればよいですか?

これは私が考えていることです:

>>> remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
[1, 3, 4, 3]

回答:


506

機能的アプローチ:

Python 3.x

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter((2).__ne__, x))
[1, 3, 3, 4]

または

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter(lambda a: a != 2, x))
[1, 3, 3, 4]

Python 2.x

>>> x = [1,2,3,2,2,2,3,4]
>>> filter(lambda a: a != 2, x)
[1, 3, 3, 4]

120
filter + lambdaに対してリスト内包表記を使用します。前者は一般的に効率的であることに加えて、より読みやすくなっています。
habnabit 2009

17
s / generally / generally being /
habnabit 2009

99
:このようなhabnabitの提案のルックスのためのコード[y for y in x if y != 2]
coredumperror

8
私はこのソリューションを最高とは言いません。リストの内包表記は、コードをざっと目を通しながら、より速く簡単に理解できます。これは、PythonよりもむしろPerlの方法に近いでしょう。
Peter Nimroot

3
-1は、直接呼び出し__ne__ます。2つの値を比較することは、単に通話よりもはるかに複雑なプロセスである__eq__か、__ne__そのうちの一つに。数値を比較するだけなので、ここでは正しく機能する可能性がありますが、一般的なケースではそれは正しくなく、バグです。
Aran-Fey

212

リスト内包表記を使用できます。

def remove_values_from_list(the_list, val):
   return [value for value in the_list if value != val]

x = [1, 2, 3, 4, 2, 2, 3]
x = remove_values_from_list(x, 2)
print x
# [1, 3, 4, 3]

7
チェックせずにアイテムを削除するにはどうすればよいですか?
Alexander Ljungberg、

18
これは元のリストを変更しませんが、新しいリストを返します。
ジョンY

6
@Selinap:いいえ、リストを1回だけスキャンするため、これは最適です。元のコードでは、in演算子とremoveメソッドの両方がリスト全体をスキャンし(一致が見つかるまで)、その結果、リストを何度もスキャンすることになります。
John Kugelman、

4
@ mhawke、@ John Y:x =の代わりにx [:] = ...を使用するだけで、名前 'x'を再バインドするのではなく「インプレース」になります(速度は基本的に同じであり、xよりもはるかに高速です) .removeは可能です!!!)。
Alex Martelli、

10
6年間のPythonの後でまだラムダスを理解できないので、私はこれに賛成票を投じます:)
Benjamin

107

効率的なリスト内包(またはジェネレーター式)を使用しながら、元のリストを変更する必要がある場合は、スライス割り当てを使用できます。

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]

1
@Selinap:フィルターはリストを変更せず、新しいリストを返します。
EM

フィルターおよびリスト内包表記はリストを変更しません。スライスの割り当ては行います。と元の例はありません。
A. Coady

7
xが参照するリストを変更するので、これが好きです。そのリストへの他の参照がある場合、それらも影響を受けます。これはx = [ v for v in x if x != 2 ]、新しいリストを作成し、それを参照するようにxを変更して、元のリストを変更しないという提案とは対照的です。
Hannes

40

より抽象的な方法で最初の投稿のソリューションを繰り返す:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]

19
ただし、O(n * n)です。
Hannes、2016

@Hannesは、ループを1回だけ通過すると同時にアイテムを削除するので、O(n)ではないでしょうか?
ペンタ

1
考えてくださいx = [1] * 10000 + [2] * 1000。ループ本体は1000回実行され、.remove()は呼び出されるたびに10000要素をスキップする必要があります。それは私にはO(n * n)のようなにおいがしますが、証拠ではありません。証明は、リストの2の数がその長さに比例すると仮定することだと思います。その比例係数は、big-O表記では消えます。ただし、リスト内の2の定数数が最も多いのはO(n ^ 2)ではなく、O(n)であるO(2n)のみです。
ハンネス

23

簡単な解決策を見る

>>> [i for i in x if i != 2]

これは、xなしのすべての要素を含むリストを返します2


11

上記のすべての回答(Martin Anderssonを除く)は、元のリストからアイテムを削除するのではなく、目的のアイテムを含まない新しいリストを作成します。

>>> import random, timeit
>>> a = list(range(5)) * 1000
>>> random.shuffle(a)

>>> b = a
>>> print(b is a)
True

>>> b = [x for x in b if x != 0]
>>> print(b is a)
False
>>> b.count(0)
0
>>> a.count(0)
1000

>>> b = a
>>> b = filter(lambda a: a != 2, x)
>>> print(b is a)
False

これは、リストへの他の参照がぶらぶらしている場合に重要になる可能性があります。

リストを適切に変更するには、次のような方法を使用します

>>> def removeall_inplace(x, l):
...     for _ in xrange(l.count(x)):
...         l.remove(x)
...
>>> removeall_inplace(0, b)
>>> b is a
True
>>> a.count(0)
0

速度に関する限り、私のラップトップでの結果は(1000エントリが削除された5000エントリリストにすべて)

  • リスト内包表記-〜400us
  • フィルター-〜900us
  • .remove()ループ-50ms

したがって、.removeループは約100倍遅くなります........うーん、おそらく別のアプローチが必要です。私が見つけた最速の方法はリスト内包表記を使用することですが、元のリストの内容を置き換えます。

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeall_replace()-450us

では、古いアドレスの下に新しいリストを再割り当てしないのはなぜですか?def remove_all(x, l): return [y for y in l if y != x]その後l = remove_all(3,l)
16年

@Dannidこれは、最初のコードボックスの2番目の方法です。新しいリストが作成され、古いリストは変更されません。リストへの他の参照はフィルタリングされないままになります。
Paul S

ああ、そうです。メソッドの定義に夢中になり、すでに行った簡単な割り当てを見落としました。
ダニード2016年

7

あなたはこれを行うことができます

while 2 in x:   
    x.remove(2)

3
リストには、2の2 * nのn倍の出現を横断しなければならないのでそれは、悪いソリューションです
cxxl

トラバースしているリストに追加または削除することはお勧めしません。悪い習慣私見。
Aman Mathur

5

読みやすさを犠牲にして、このバージョンはリストを再確認するようにしばらく強制しないので少し高速だと思います。したがって、とにかく削除とまったく同じ作業を行う必要があります:

x = [1, 2, 3, 4, 2, 2, 3]
def remove_values_from_list(the_list, val):
    for i in range(the_list.count(val)):
        the_list.remove(val)

remove_values_from_list(x, 2)

print(x)

私の測定によれば、コードに表示するリストの場合、このアプローチはリスト内包表記メソッド(コピーを返す)よりも約36%遅くなります。
djsmith 2012年

良いことに気づきました。しかし、それはあなたの判断を下したかもしれないと思うので、私は自分のバージョンを質問作者の最初の提案と比較していました。
Martin Andersson

4

Numpyアプローチと1.000.000要素のリスト/配列に対するタイミング:

タイミング:

In [10]: a.shape
Out[10]: (1000000,)

In [13]: len(lst)
Out[13]: 1000000

In [18]: %timeit a[a != 2]
100 loops, best of 3: 2.94 ms per loop

In [19]: %timeit [x for x in lst if x != 2]
10 loops, best of 3: 79.7 ms per loop

結論:リスト内包表記アプローチと比較して、numpyは(私のノートブックで)27倍高速です。

通常のPythonリストlstをnumpy配列に変換する場合はPS :

arr = np.array(lst)

セットアップ:

import numpy as np
a = np.random.randint(0, 1000, 10**6)

In [10]: a.shape
Out[10]: (1000000,)

In [12]: lst = a.tolist()

In [13]: len(lst)
Out[13]: 1000000

小切手:

In [14]: a[a != 2].shape
Out[14]: (998949,)

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949

4
a = [1, 2, 2, 3, 1]
to_remove = 1
a = [i for i in a if i != to_remove]
print(a)

おそらく最もパイソンではないが、それでも私にとっては最も簡単だ


3

重複するオカレンスをすべて削除し、リストに残しておくには:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

プロジェクトオイラーに使用した関数は次のとおりです。

def removeOccurrences(e):
  return list(set(e))

2
250kの値を持つベクトルでこれを行う必要があり、それは魅力のように機能します。
rschwieb 2013年

1
答えは:はい!そして、有能なプログラマーにとって完全に狂ったように聞こえるベクトルがあるかどうか、私は完全に理解しています。解決策の最適化について心配することなく、数学者としてそこで問題に取り組みます。これは、標準よりも長い解決策につながる可能性があります。(5分を超えるソリューションには我慢できませんが)
rschwieb 2013年

6
これにより、リストから順序が削除されます。
asmeurer 2013

4
@JaredBurrowsは、おそらく現状では質問に答えないためですが、まったく異なる質問です。
drevicko 14年

6
-1、これはOPの質問に対する回答ではありません。それは完全に異なる問題である重複を削除するソリューションです。
Anoyz

2

これは、リストの順序を気にしない場合は、他の方法よりもおそらく高速だと思います。最終的な順序を気にして、元のインデックスを保存し、それによって再ソートする場合。

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]

2
あなたも開始インデックスだけではなく、0必要があるので、私はどこyour'eが起こって理解しますが、このコードは動作しません
Shedokan

2
for i in range(a.count(' ')):
    a.remove(' ')

ずっとシンプルだと思います。


2
わかりやすくするために回答を編集してください。推奨コードが正確に何をするのか、なぜ機能するのか、なぜこれが推奨なのかを明確にしてください。また、コードを残りの回答から明確に識別できるように、質問を正しくフォーマットしてください。
Ortund、2016年

2

しましょう

>>> x = [1, 2, 3, 4, 2, 2, 3]

以前に投稿された最も簡単で効率的なソリューションは

>>> x[:] = [v for v in x if v != 2]
>>> x
[1, 3, 4, 3]

より少ないメモリを使用する必要がありますが遅くなる別の可能性は

>>> for i in range(len(x) - 1, -1, -1):
        if x[i] == 2:
            x.pop(i)  # takes time ~ len(x) - i
>>> x
[1, 3, 4, 3]

エントリが10%一致する長さ1000および100000のリストのタイミング結果:0.16対0.25ミリ秒、23対123ミリ秒。

長さ1000のタイミング

長さ100000のタイミング


1

Pythonリストからすべての値を削除します

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list():
    for list in lists:
      if(list!=7):
         print(list)
remove_values_from_list()

結果: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

または、

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list(remove):
    for list in lists:
      if(list!=remove):
        print(list)
remove_values_from_list(7)

結果: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


「Pythonは、100%の精度で機能する関数内で各ifループにネストされています!」
rafiqul786 2016

要素を印刷するだけでリストを変更することはありません。また、リストをリストとして名前を付けることは混乱を招きます
kon psych

0

ビルトインfilterがないか、余分なスペースを使用したくない場合、線形ソリューションが必要です...

def remove_all(A, v):
    k = 0
    n = len(A)
    for i in range(n):
        if A[i] !=  v:
            A[k] = A[i]
            k += 1

    A = A[:k]

0
hello =  ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
#chech every item for a match
for item in range(len(hello)-1):
     if hello[item] == ' ': 
#if there is a match, rebuild the list with the list before the item + the list after the item
         hello = hello[:item] + hello [item + 1:]
print hello

['こんにちは世界']


説明を付けて回答を詳しく説明してください。
parlad

0

私はリストのためにこれをやった。私は初心者です。少し上級のプログラマーでも、このような関数を確実に作成できます。

for i in range(len(spam)):
    spam.remove('cat')
    if 'cat' not in spam:
         print('All instances of ' + 'cat ' + 'have been removed')
         break

0

delまたはを使用して、すべてをインプレース削除することもできますpop

import random

def remove_values_from_list(lst, target):
    if type(lst) != list:
        return lst

    i = 0
    while i < len(lst):
        if lst[i] == target:
            lst.pop(i)  # length decreased by 1 already
        else:
            i += 1

    return lst

remove_values_from_list(None, 2)
remove_values_from_list([], 2)
remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)], 2)
print(len(lst))

効率性のために:

In [21]: %timeit -n1 -r1 x = random.randrange(0,10)
1 loop, best of 1: 43.5 us per loop

In [22]: %timeit -n1 -r1 lst = [random.randrange(0, 10) for x in range(1000000)]
g1 loop, best of 1: 660 ms per loop

In [23]: %timeit -n1 -r1 lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)]
    ...: , random.randrange(0,10))
1 loop, best of 1: 11.5 s per loop

In [27]: %timeit -n1 -r1 x = random.randrange(0,10); lst = [a for a in [random.randrange(0, 10) for x in
    ...:  range(1000000)] if x != a]
1 loop, best of 1: 710 ms per loop

インプレースバージョンremove_values_from_list()は追加のメモリを必要としないことがわかりますが、実行には非常に多くの時間がかかります。

  • インプレース削除値には11秒
  • メモリ内に新しいリストを割り当てるリスト内包表記の場合は710ミリ秒

0

時間と空間の複雑さについて最適な答えを誰も投稿していないので、試してみようと思いました。これは、新しい配列を作成せずに効率的な時間で特定の値のすべての発生を削除するソリューションです。欠点は、要素が順序を維持しないことです。

時間の複雑さ:O(n)
追加の空間の複雑さ:O(1)

def main():
    test_case([1, 2, 3, 4, 2, 2, 3], 2)     # [1, 3, 3, 4]
    test_case([3, 3, 3], 3)                 # []
    test_case([1, 1, 1], 3)                 # [1, 1, 1]


def test_case(test_val, remove_val):
    remove_element_in_place(test_val, remove_val)
    print(test_val)


def remove_element_in_place(my_list, remove_value):
    length_my_list = len(my_list)
    swap_idx = length_my_list - 1

    for idx in range(length_my_list - 1, -1, -1):
        if my_list[idx] == remove_value:
            my_list[idx], my_list[swap_idx] = my_list[swap_idx], my_list[idx]
            swap_idx -= 1

    for pop_idx in range(length_my_list - swap_idx - 1):
        my_list.pop() # O(1) operation


if __name__ == '__main__':
    main()

-1

スピードについて!

import time
s_time = time.time()

print 'start'
a = range(100000000)
del a[:]
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 3.25

s_time = time.time()
print 'start'
a = range(100000000)
a = []
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 2.11

-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

Python 3のみ


2
陽気に、これは尋ねられた質問の範囲内にあり、正しいです。
Erich

それがどのように正しいのかわかりません。これにより、値のすべてのオカレンスではなく、すべてのアイテムがリストから削除されます
ジョージー

-3

どうしたの:

Motor=['1','2','2']
For i in Motor:
       If i  != '2':
       Print(i)
Print(motor)

anacondaの使用


2
他のユーザーがその機能を理解できるように、コード行を説明してください。ありがとう!
Ignacio Ara

このコードはリストから何も削除しません。
ジョージー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.