1077

Python には、次のような 2 つのリストがあります。

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']

2 番目のリストには存在しない最初のリストの項目を含む 3 番目のリストを作成する必要があります。私が取得しなければならない例から

temp3 = ['Three', 'Four']

サイクルとチェックなしで簡単な方法はありますか?

4

31 に答える 31

1567

temp1にあるが含まれていない要素を取得するにはtemp2 :

In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']

非対称であることに注意してください:

In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1]) 

あなたが期待する/等しくしたい場所set([1, 3])。答えとして必要な場合はset([1, 3])、 を使用できますset([1, 2]).symmetric_difference(set([2, 3]))

于 2010-08-11T19:40:00.620 に答える
576

既存のソリューションはすべて、次のいずれかを提供します。

  • O(n*m) パフォーマンスよりも高速です。
  • 入力リストの順序を保持します。

しかし、これまでのところ、両方を備えたソリューションはありません。両方が必要な場合は、これを試してください:

s = set(temp2)
temp3 = [x for x in temp1 if x not in s]

性能テスト

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)

結果:

4.34620224079 # ars' answer
4.2770634955  # This answer
30.7715615392 # matt b's answer

私が提示した方法と順序の保存は、不要な集合の構築を必要としないため、集合減算よりも (わずかに) 高速です。最初のリストが 2 番目のリストよりかなり長く、ハッシュが高価な場合、パフォーマンスの違いはより顕著になります。これを示す 2 番目のテストを次に示します。

init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''

結果:

11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
于 2010-08-11T19:44:47.700 に答える
113
temp3 = [item for item in temp1 if item not in temp2]
于 2010-08-11T19:40:27.803 に答える
23

2 つのリスト (list1 と list2 など) の違いは、次の単純な関数を使用して見つけることができます。

def diff(list1, list2):
    c = set(list1).union(set(list2))  # or c = set(list1) | set(list2)
    d = set(list1).intersection(set(list2))  # or d = set(list1) & set(list2)
    return list(c - d)

また

def diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))  # or return list(set(list1) ^ set(list2))

上記の関数を使用すると、diff(temp2, temp1)またはを使用して違いを見つけることができますdiff(temp1, temp2)。どちらも結果が得られ['Four', 'Three']ます。リストの順序や、どのリストを最初に指定するかを気にする必要はありません。

Python ドキュメント リファレンス

于 2012-08-17T11:38:00.637 に答える
23

違いが再帰的に必要な場合に備えて、Python 用のパッケージを作成しました: https://github.com/seperman/deepdiff

インストール

PyPi からインストールします。

pip install deepdiff

使用例

輸入中

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2

同じオブジェクトが空を返す

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}

アイテムの種類が変更されました

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                 'newvalue': '2',
                                 'oldtype': <class 'int'>,
                                 'oldvalue': 2}}}

アイテムの値が変更されました

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

アイテムの追加および/または削除

>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
 'dic_item_removed': ['root[4]'],
 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

弦違い

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                      "root[4]['b']": { 'newvalue': 'world!',
                                        'oldvalue': 'world'}}}

弦違い2

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                '+++ \n'
                                                '@@ -1,5 +1,4 @@\n'
                                                '-world!\n'
                                                '-Goodbye!\n'
                                                '+world\n'
                                                ' 1\n'
                                                ' 2\n'
                                                ' End',
                                        'newvalue': 'world\n1\n2\nEnd',
                                        'oldvalue': 'world!\n'
                                                    'Goodbye!\n'
                                                    '1\n'
                                                    '2\n'
                                                    'End'}}}

>>> 
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
--- 
+++ 
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
 1
 2
 End

タイプチェンジ

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                      'newvalue': 'world\n\n\nEnd',
                                      'oldtype': <class 'list'>,
                                      'oldvalue': [1, 2, 3]}}}

リストの違い

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}

リストの違い 2:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
  'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                      "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}

順序または重複を無視して違いをリストする: (上記と同じ辞書を使用)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}

辞書を含むリスト:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
  'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}

セット:

>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}

名前付きタプル:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}

カスタム オブジェクト:

>>> class ClassA(object):
...     a = 1
...     def __init__(self, b):
...         self.b = b
... 
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>> 
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

追加されたオブジェクト属性:

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
于 2014-09-27T21:30:22.630 に答える
17

これを試して:

temp3 = set(temp1) - set(temp2)
于 2010-08-11T19:39:59.867 に答える
15

本当にパフォーマンスを調べている場合は、numpy を使用してください。

リスト、numpy、pandas を比較した github の要旨としての完全なノートブックを次に示します。

https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451

ここに画像の説明を入力

于 2015-08-07T15:30:58.147 に答える
13

現在のソリューションはどれもタプルを生成しないので、私は投げ込みます:

temp3 = tuple(set(temp1) - set(temp2))

または:

#edited using @Mark Byers idea. If you accept this one as answer, just accept his instead.
temp3 = tuple(x for x in temp1 if x not in set(temp2))

この方向で答えを生み出す他の非タプルのように、それは秩序を維持します

于 2010-08-11T19:42:06.130 に答える
11

これは、Mark のリスト内包表記よりもさらに高速になる可能性があります。

list(itertools.filterfalse(set(temp2).__contains__, temp1))
于 2011-08-18T06:01:28.530 に答える
5

これは別の解決策です:

def diff(a, b):
    xa = [i for i in set(a) if i not in b]
    xb = [i for i in set(b) if i not in a]
    return xa + xb
于 2014-03-29T02:36:31.237 に答える
3

変更セットのようなものが必要な場合は...カウンターを使用できます

from collections import Counter

def diff(a, b):
  """ more verbose than needs to be, for clarity """
  ca, cb = Counter(a), Counter(b)
  to_add = cb - ca
  to_remove = ca - cb
  changes = Counter(to_add)
  changes.subtract(to_remove)
  return changes

lista = ['one', 'three', 'four', 'four', 'one']
listb = ['one', 'two', 'three']

In [127]: diff(lista, listb)
Out[127]: Counter({'two': 1, 'one': -1, 'four': -2})
# in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s

In [128]: diff(listb, lista)
Out[128]: Counter({'four': 2, 'one': 1, 'two': -1})
# in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two"
于 2015-12-17T22:20:50.253 に答える