リストの重複を削除する


995

ほとんどの場合、リストに重複があるかどうかを確認するプログラムを作成する必要があり、リストに重複がある場合はそれらを削除し、重複/削除されなかったアイテムを含む新しいリストを返します。これは私が持っているものですが、正直に言うと何をすべきかわかりません。

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t

22
説明では、「リスト」で重複をチェックしていると説明されていますが、コードでは2つのリストをチェックしています。
ブレンダンロング


* set:list(set(ELEMENTS_LIST))を使用* * dictionary:list(dict.fromkeys(ELEMENTS_LIST))を使用
Shayan Amani

回答:


1641

アイテムの一意のコレクションを取得する一般的なアプローチは、を使用することsetです。セットは、個別のオブジェクトの順序付けられていないコレクションです。イテラブルからセットを作成するには、単純にそれを組み込み関数に渡すことができます。後で実際のリストが再び必要になった場合は、同様にセットを関数に渡すことができます。set()list()

次の例は、実行しようとしていることをすべてカバーする必要があります。

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

例の結果からわかるように、元の順序は維持されていません。上記のように、セット自体は順序付けられていないコレクションであるため、順序は失われます。セットをリストに変換すると、任意の順序が作成されます。

秩序の維持

順序が重要な場合は、別のメカニズムを使用する必要があります。これに対する非常に一般的な解決策は、OrderedDict挿入時にキーの順序を維持することに依存することです。

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Python 3.7以降、組み込み辞書は挿入順序も維持することが保証されているため、Python 3.7以降(またはCPython 3.6)を使用している場合は、それを直接使用することもできます。

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

これは、最初に辞書を作成し、それからリストを作成するというオーバーヘッドがあることに注意してください。実際に順序を維持する必要がない場合は、セットを使用する方がよい場合があります。これにより、操作する操作が多くなります。重複を削除するときに順序を維持するための詳細と代替方法については、この質問を確認してください。


最後にsetOrderedDict/ dictソリューションだけでなく、アイテムもハッシュ可能である必要があることに注意してください。これは通常、それらが不変でなければならないことを意味します。ハッシュ可能ではないアイテム(リストオブジェクトなど)を処理する必要がある場合は、基本的にすべてのアイテムをネストされたループ内の他のすべてのアイテムと比較する必要がある遅いアプローチを使用する必要があります。


4
これはハッシュ化できないリスト要素(リストのリストなど)では機能しません
KNejad

3
@KNejadそれが最後の段落で述べていることです。
突く

おっと。全部読んだ方がいい。結局、リストの代わりにタプルを使用することになったので、このアプローチはまだ機能します。
KNejad

これを例に追加すると、t = [3、2、1、1、2、5、6、7、8]の違いがはっきりとわかります。
sailfish009

「...最初に辞書を作成することのオーバーヘッド...実際に順序を維持する必要がない場合は、セットを使用した方がよいでしょう。」—実際にそれが真実であるかどうか知りたくて、これをプロファイリングしました。私のタイミングは、実際にはセットがわずかに速いことを示しています。1Mループで1.12 µs(ループ)(セット)に対して1.12 µs、1Mループで1.53 µs(ループ)(絶対時間差は100万回で約4秒)。したがって、タイトな内部ループでこれを実行している場合は気にしてもよいでしょう。
millerdev

414

Python 2.7では、元の順序を維持しながら反復可能オブジェクトから重複を削除する新しい方法は次のとおりです。

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

Python 3.5では、OrderedDictにC実装があります。私のタイミングは、これがPython 3.5のさまざまなアプローチの中で最速かつ最短であることを示しています。

Python 3.6では、通常の辞書が秩序あるコンパクトなものになりました。(この機能はCPythonとPyPyに適用されますが、他の実装には存在しない場合があります)。これにより、順序を維持しながら重複排除を行う新しい最速の方法が得られます。

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

Python 3.7では、通常のdictはすべての実装で順序付けされることが保証されています。 したがって、最短かつ最速のソリューションは次のとおりです。

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

10
これがアイテムを整理する唯一の方法だと思います。
Herberth Amaral

19
@HerberthAmaral:それは真実からはほど遠いです。順序を維持しながら、Pythonのリストから重複
Martijn Pieters

5
@MartijnPieters修正:これは、アイテムを整理するための唯一の簡単な方法だと思います。
Herberth Amaral 2013

12
これについても、元のリストのコンテンツはハッシュ可能である必要があります
Davide

@Davideが述べたように、元のリストはハッシュ可能でなければなりません。つまり、これは辞書のリストでは機能しません。TypeError: unhashable type: 'dictlist'
CraZ

187

それはワンライナーです:list(set(source_list))トリックを行います。

A setは重複する可能性がないものです。

更新:順序を維持するアプローチは2行です。

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

ここではOrderedDict、キーの挿入順序を記憶し、特定のキーの値が更新されても変更しないという事実を使用します。True値として挿入しますが、何でも挿入できます。値は使用されません。(setのようにたくさんの作品dictも、無視された値を持ちます。)


5
これsource_listはハッシュ可能な場合にのみ機能します。
エイドリアンキースター

@AdrianKeister:これは本当です。妥当な等価セマンティクスを持っているがハッシュ化できないオブジェクトがあります(リストなど)。OTOHは、hastableのようなショートカットを使用できない場合、すべての要素を現在知られているすべての一意の要素と比較するだけの2次アルゴリズムになります。これは、特に多くの重複がある場合、短い入力では完全に問題ありません。
9000

そうです。この非常に一般的なユースケースを考慮に入れれば、あなたの答えはより高品質になると思います。
エイドリアンキースター

94
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
       if i not in s:
          s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]

33
このメソッドはO(n ^ 2)時間で動作するため、大きなリストでは非常に遅いことに注意してください。
dotancohen 2013

@Chris_Rands:ハッシュ化できないfrozensetコンテンツでは動作しません。を使用しても、まだハッシュ化できないエラーが発生しfrozensetます。
エイドリアンキースター


41

重複の最初の要素の順序を保持する新しいリストを作成するには L

newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]

たとえばif L=[1, 2, 2, 3, 4, 2, 4, 3, 5]それnewlistから[1,2,3,4,5]

これにより、新しい要素を追加する前に、以前にリストに表示されていない各要素がチェックされます。また、インポートは必要ありません。


3
これはO(n ^ 2)の時間の複雑さを持っています。との答えはsetOrderedDict償却時間の複雑さが低くなる可能性があります。
blubberdiblub 2017

私は自分のコードでこのソリューションを使用し、うまく機能しましたが、時間がかかると思います
Gerasimos Ragavanis 2018

@blubberdiblubは、setとOrderedDictに存在するコード効率の良いメカニズムによって、時間の消費を削減できることを説明できますか?(ロードのオーバーヘッドを除く)
ilias iliadis

@iliasiliadis setおよびdictの通常の実装で、ハッシュまたは(バランスのある形式の)ツリーを使用します。セットまたはディクショナリを構築してそれを(複数回)検索することを検討する必要がありますが、通常、償却後の複雑さはO(n ^ 2)よりも低くなります。単純な用語で「償却」とは、平均して意味する(平均的なケースよりも複雑で最悪のケースになる可能性がある)。これは、アイテムの数が多い場合にのみ関係します。
blubberdiblub

25

同僚は、本日のコードレビューのために、承認された回答をコードの一部として私に送信しました。問題の答えの優雅さには確かに感心しますが、そのパフォーマンスには満足していません。私はこの解決策を試しました(ルックアップ時間を短縮するためにセットを使用しています)

def ordered_set(in_list):
    out_list = []
    added = set()
    for val in in_list:
        if not val in added:
            out_list.append(val)
            added.add(val)
    return out_list

効率を比較するために、100の整数のランダムなサンプルを使用しました-62は一意でした

from random import randint
x = [randint(0,100) for _ in xrange(100)]

In [131]: len(set(x))
Out[131]: 62

ここに測定の結果があります

In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop

In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop

さて、セットがソリューションから削除されるとどうなりますか?

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

結果はOrderedDictほど悪くありませんが、元のソリューションの3倍以上です

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop

ループ比較を高速化するためにset quick lookupを使用するのは素晴らしいことです。順序が問題ではない場合、list(set(x))はこれよりも6倍高速です
Joop

@Joop、それは私の同僚に対する私の最初の質問でした-順序は重要です。そうでなければ、それはささいな問題だったでしょう
火山

興味がある人のための順序集合の最適化バージョン、:def unique(iterable):; seen = set(); seen_add = seen.add; return [item for item in iterable if not item in seen and not seen_add(item)]
DrD

25

PandasとNumpyを使用したソリューションもあります。どちらもnumpy配列を返すため.tolist()、リストが必要な場合は関数を使用する必要があります。

t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']

パンダのソリューション

パンダ機能の使用unique()

import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']

Numpyソリューション

numpy関数を使用しますunique()

import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']

numpy.unique()も値をソートすることに注意してください。したがって、リストt2はソートされて返されます。この回答のように順序を保存して使用したい場合:

_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']

ソリューションは他のソリューションに比べてそれほどエレガントではありませんが、pandas.unique()と比較すると、numpy.unique()を使用すると、選択した1つの軸に沿ってネストされた配列が一意かどうかを確認することもできます。


これは、リストを混乱したnumpy配列に変換し、文字列には機能しません。
user227666 14

1
@ user227666あなたのレビューに感謝しますが、それは真実ではありません。文字列でも機能し、リストを取得したい場合は.tolistを追加できます...
GM

1
これは、大槌で蜂を殺そうとするようなものだと思います。確かに動作します!しかし、この目的のためだけにライブラリーをインポートするのは少しやり過ぎかもしれません。
Debosmit Ray 2016

@DebosmitRayは、通常はnumpyで作業し、numpy配列で作業する必要があるデータサイエンスで作業する場合に役立ちます。
GM、

2020年のベストアンサー@DebosmitRay心を変え、できる限りnumpy / pandasを使用してほしい
Egos

21

別の方法:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]

1
最新のPythonバージョン(2.7以上だと思いますが、はっきりとは覚えていません)ではkeys()、リストではなくディクショナリビューオブジェクトを返します。
ダスティンワイアット

16

シンプルで簡単:

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]

出力:

>>> cleanlist 
[1, 2, 3, 5, 6, 7, 8]

5
それでも2次の複雑さin-O(n)演算であり、cleanlist最大n数=>最悪の場合〜O(n ^ 2)
jermenkoo

6
リスト内包表記を副作用に使用しないでください。
ジャン=フランソワ・ファーブル

13

この回答では、2つのセクションがあります。2つのユニークなソリューションと、特定のソリューションの速度のグラフです。

重複するアイテムの削除

これらの回答のほとんどは、ハッシュ可能な重複アイテムのみを削除しますが、この質問は、ハッシュ可能なアイテムだけが必要というわけではないことを意味しません。つまりハッシュ可能なアイテムを必要としないソリューションをいくつか提供します。

collections.Counterは標準ライブラリの強力なツールで、これに最適です。Counterが含まれているソリューションは他に1つしかありません。ただし、そのソリューションはハッシュ可能なキーにも限定されます。

Counterでハッシュできないキーを許可するために、オブジェクトのデフォルトのハッシュ関数を取得しようとするContainerクラスを作成しましたが、失敗した場合は、アイデンティティ関数を試行します。また、eqおよびハッシュ方式も定義します。これは、ソリューションでハッシュ化できないアイテムを許可するのに十分なはずです。ハッシュ不可のオブジェクトは、ハッシュ可能であるかのように扱われます。ただし、このハッシュ関数はハッシュ化できないオブジェクトにIDを使用します。つまり、両方ともハッシュ化できない2つの等しいオブジェクトは機能しません。これをオーバーライドして、同等の変更可能な型のハッシュを使用するように変更することをお勧めします(hash(tuple(my_list))if my_listis a list を使用するなど)。

私も2つの解決策を作りました。「OrderedCounter」というOrderedDictとCounterの両方のサブクラスを使用して、アイテムの順序を保持する別のソリューション。さて、ここに関数があります:

from collections import OrderedDict, Counter

class Container:
    def __init__(self, obj):
        self.obj = obj
    def __eq__(self, obj):
        return self.obj == obj
    def __hash__(self):
        try:
            return hash(self.obj)
        except:
            return id(self.obj)

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

def remd(sequence):
    cnt = Counter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

def oremd(sequence):
    cnt = OrderedCounter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

remdは順序付けされていないソートであり、oremdは順序付けされたソートです。どちらが速いかははっきりとわかりますが、とにかく説明します。非順序付けされたソートはわずかに高速です。順序を必要としないため、保持するデータが少なくなります。

次に、各回答の速度比較も表示したいと思います。だから、今からやります。

どの関数が最速ですか?

重複を取り除くために、いくつかの回答から10個の関数を収集しました。各関数の速度を計算し、matplotlib.pyplotを使用してグラフに入れました。

これを3回のグラフに分けました。ハッシュ可能とは、ハッシュできるオブジェクトのことであり、ハッシュ不可能とは、ハッシュできないオブジェクトのことです。順序付けられたシーケンスは順序を保持するシーケンスであり、順序付けられていないシーケンスは順序を保持しません。さて、ここにいくつかの用語があります:

Unordered Hashableは、重複を削除するすべてのメソッド用で、必ずしも順序を維持する必要はありませんでした。アンハッシュ可能にするために機能する必要はありませんでしたが、機能しました。

Ordered Hashableは、リスト内のアイテムの順序を維持する任意のメソッド用でしたが、unhashableで機能する必要はありませんでしたが、機能しました。

Ordered Unhashableは、リスト内のアイテムの順序を保持し、ハッシュ化できないものに対して機能する方法です。

y軸は、かかった秒数です。

x軸は、関数が適用された番号です。

順序付けされていないハッシャブルと順序付けされたハッシャブルのシーケンスを次の理解度で生成しました。 [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]

順序付けられたハッシュ化不可の場合: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]

範囲内に「ステップ」があることに注意してください。これがないと、10倍の時間がかかります。また、個人的な見解では、少し読みやすくなったのではないかと思いました。

また、凡例のキーは、関数の最も重要な部分として私が推測しようとしたものであることに注意してください。どんな機能が最悪または最高ですか?グラフはそれ自体を物語っています。

これで解決すると、ここにグラフがあります。

順序付けされていないハッシュ可能

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

注文したハッシュ可能

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

順序付けられたハッシュ不可

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


11

リストに口述があったので、上記のアプローチは使用できませんでした。エラーが発生しました:

TypeError: unhashable type:

したがって、注文を気にする場合や、一部のアイテムはハッシュ化できません。次に、これが便利な場合があります。

def make_unique(original_list):
    unique_list = []
    [unique_list.append(obj) for obj in original_list if obj not in unique_list]
    return unique_list

一部の人は、副作用を伴うリスト内包表記を適切な解決策ではないと見なす場合があります。ここに代替があります:

def make_unique(original_list):
    unique_list = []
    map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
    return unique_list

6
map副作用があると、副作用があるlistcompよりもさらに誤解を招きます。また、lambda x: unique_list.append(x)通過するのはただの不格好で遅い方法unique_list.appendです。
abarnert 2014年

要素を1行で追加する非常に便利な方法です。ありがとうございます。
ZLNK、2017年

2
@ZLNKお願いします。これを使用しないでください。概念的に見苦しいだけでなく、実際には大きなリストを作成し、基本的な反復を実行するためだけに破棄するため、非常に非効率的です。
Eli Korvigo

10

これまでに見てきたすべての順序を維持するアプローチは、単純な比較(せいぜいO(n ^ 2)の時間の複雑さ)を使用するか、ハッシュ可能な入力に制限される重いOrderedDicts/ set+のlist組み合わせを使用します。以下は、ハッシュに依存しないO(nlogn)ソリューションです。

更新により、key引数、ドキュメント、Python 3の互換性が追加されました。

# from functools import reduce <-- add this import on Python 3

def uniq(iterable, key=lambda x: x):
    """
    Remove duplicates from an iterable. Preserves order. 
    :type iterable: Iterable[Ord => A]
    :param iterable: an iterable of objects of any orderable type
    :type key: Callable[A] -> (Ord => B)
    :param key: optional argument; by default an item (A) is discarded 
    if another item (B), such that A == B, has already been encountered and taken. 
    If you provide a key, this condition changes to key(A) == key(B); the callable 
    must return orderable objects.
    """
    # Enumerate the list to restore order lately; reduce the sorted list; restore order
    def append_unique(acc, item):
        return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc 
    srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
    return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))] 

しかし、このソリューションには注文可能な要素が必要です。私はそれを使用して、リストのリストを一意化しtuple()ます。リストを作成してハッシュするのは面倒です。| | | | -一般的に言って、ハッシュプロセスにはデータ全体のサイズに比例する時間がかかりますが、このソリューションではリストの長さにのみ依存してO(nlog(n))時間がかかります。
loxaxs 2016年

セットベースのアプローチは、並べ替え+一意の検出よりも安価(O(n log n))、または安価だと思います。(ただし、このアプローチは、並列化がはるかに良くなります。)また、最初の順序を正確に保持するわけではありませんが、予測可能な順序を提供します。
9000

@ 9000それは本当です。ハッシュテーブルベースのアプローチの時間の複雑さについては言及していません。これは明らかにO(n)です。ここでは、ハッシュテーブルを組み込んだ多くの答えを見つけることができます。ただし、オブジェクトをハッシュ可能にする必要があるため、これらはユニバーサルではありません。さらに、それらはより多くのメモリを消費します。
Eli Korvigo 2017

この回答を読んで理解するには時間がかかります。インデックスを使用していないときに列挙することに意味がありますか?reduce() すでに分別回収に取り組んでいるsrt_enumあなたが適用されなかった理由、sorted再び?
ブラヨニ

@Brayoni最初の並べ替えは、等しい値をグループ化するためにあり、2番目の並べ替えは、最初の順序を復元するためにあります。列挙は、元の相対順序を追跡するために必要です。
Eli Korvigo

9

順序を維持し、外部モジュールを使用しない場合は、これを行う簡単な方法を次に示します。

>>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
>>> list(dict.fromkeys(t))
[1, 9, 2, 3, 4, 5, 6, 7, 8]

注:このメソッドは表示の順序を保持するため、上記のように、最初に表示されたため、1つ後に9つが続きます。しかし、これはあなたがすることで得られるのと同じ結果です

from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))

しかし、それははるかに短く、より速く実行されます。

これは、fromkeys関数が新しいキーを作成しようとするたびに、値がすでに存在する場合は単に上書きするため機能します。ただし、これはディクショナリにはまったく影響しませんfromkeys。すべてのキーが値を持つディクショナリを作成するNoneため、この方法ですべての重複を効果的に排除します。


また、それを試してみて、ここで
vineeshvs

8

これを行うこともできます:

>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]

上記が機能する理由は、indexメソッドが要素の最初のインデックスのみを返すためです。重複する要素には、より高いインデックスがあります。ここを参照してください

list.index(x [、start [、end]])
値がxである最初のアイテムのリストでゼロから始まるインデックスを返します。そのようなアイテムがない場合、ValueErrorを発生させます。


これはひどく非効率的です。list.index線形時間演算であり、解を2次式にします。
Eli Korvigo 2018

あなたが正しい。しかし、私は、このソリューションが注文を保存する1つのライナーになることを意図していることもかなり明白だと思います。他のすべてはすでにここにあります。
Atonal 2018年


7

順序を保持してバリアントを削減:

リストがあると仮定します:

l = [5, 6, 6, 1, 1, 2, 2, 3, 4]

バリアントを削減(非効率的):

>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]

5倍高速ですが、より洗練されています

>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

説明:

default = (list(), set())
# user list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

reduce(reducer, l, default)[0]

7

リストから重複を削除する最善の方法は、Pythonで使用可能なset()関数を使用して、そのセットをリストに再度変換することです。

In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']

@MeetZaveri嬉しいです!
Anurag Misra

新しいリストとセットのインスタンス化は無料ではありません。これをすばやく連続して(つまり、非常にタイトなループで)何度も実行し、リストが非常に小さい場合はどうなりますか?
Z4層

6

次の関数を使用できます。

def rem_dupes(dup_list): 
    yooneeks = [] 
    for elem in dup_list: 
        if elem not in yooneeks: 
            yooneeks.append(elem) 
    return yooneeks

my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']

使用法:

rem_dupes(my_list)

['this'、 'is'、 'a'、 'list'、 'with'、 'dupicates'、 'in'、 'the']


5

これを行うさまざまな方法を提案する他の多くの答えがありますが、それらはすべてバッチ操作であり、それらのいくつかは元の順序を捨てます。それは必要なものによっては大丈夫かもしれませんが、各値の最初のインスタンスの順序で値を反復処理したい場合、およびその場ですべての複製を一度に削除する場合は、このジェネレータ:

def uniqify(iterable):
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item

これはジェネレータ/イテレータを返すので、イテレータを使用できる場所ならどこでも使用できます。

for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
    print(unique_item, end=' ')

print()

出力:

1 2 3 4 5 6 7 8

あなたがしたい場合はlist、これを行うことができます:

unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))

print(unique_list)

出力:

[1, 2, 3, 4, 5, 6, 7, 8]

seen = set(iterable); for item in seen: yield itemほぼ確実に高速です。(私はこの特定のケースを試していませんが、それは私の推測でしょう)
dylnmc

2
@dylnmc、これはバッチ処理であり、順序も失われます。私の回答は、オンザフライで、最初に発生する順番になるように特別に意図されていました。:)
2016年

5

セットなし

data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
    if dat not in uni_data:
        uni_data.append(dat)

print(uni_data) 

5

を使用setして重複を削除できます。

mylist = list(set(mylist))

ただし、結果は順序付けされないことに注意してください。それが問題である場合:

mylist.sort()

1
あなたはただ行うことができます:mylist =
Sorted

5

もう1つのより良いアプローチは、

import pandas as pd

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)

#> [1, 2, 3, 5, 6, 7, 8]

順序は維持されます。


これはうまくいくかもしれませんが、この目的のためにパンダのような重いライブラリを使用することはやり過ぎのように思えます。
Glutexo

4

これはあまり面倒なことなく注文を気にします(OrderdDictなど)。おそらく最もPython的な方法でも、最も短い方法でもありませんが、トリックを行います:

def remove_duplicates(list):
    ''' Removes duplicate items from a list '''
    singles_list = []
    for element in list:
        if element not in singles_list:
            singles_list.append(element)
    return singles_list

1.組み込み名をシャドウしないでください(少なくともと同じくらい重要listです)。2.メソッドのスケーリングが非常に悪い:これは、の要素数が2次であるlist
Eli Korvigo 2018年

1.正解ですが、これは例です。2.正解です。それが、私が提案した理由です。ここに掲載されているすべてのソリューションには長所と短所があります。単純さや順序を犠牲にするものもあれば、スケーラビリティを犠牲にするものもあります。
cgf 2018年

これは「Shlemiel画家」アルゴリズムです...
Z4層

4

以下のコードは、リスト内の重複を削除するためのシンプルなものです

def remove_duplicates(x):
    a = []
    for i in x:
        if i not in a:
            a.append(i)
    return a

print remove_duplicates([1,2,2,3,3,4])

[1,2,3,4]を返します


2
順序を気にしない場合は、かなり時間がかかります。list(set(..))(100万パス以上)は、このソリューションに約10秒かかります-このアプローチは約12秒list(set(..))かかりますが、約2秒しかかかりません!
dylnmc 2016

@dylnmcこれもかなり古い回答の
Eli Korvigo

4

これが、返信にリストされている他の人と並ぶ最速のpythonicソリューションです。

短絡評価の実装の詳細を使用すると、十分に高速なリスト内包表記を使用できます。visited.add(item)常にNone結果として返され、として評価されるFalseため、の右側はorは常にそのような式の結果になります。

自分で時間を計る

def deduplicate(sequence):
    visited = set()
    adder = visited.add  # get rid of qualification overhead
    out = [adder(item) or item for item in sequence if item not in visited]
    return out


4

残念ながら。ここでのほとんどの回答は、順序を維持しないか、長すぎます。これは、単純な順序保持の答えです。

s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]

[x.append(i) for i in s if i not in x]
print(x)

これにより、重複が削除されたxが得られますが、順序は保持されます。


3

Python 3の非常に簡単な方法:

>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]

2
sorted(list(...))冗長です(sortedすでに暗黙的に引数を新しいに変換しlist、並べ替えてから新しいを返します。list両方を使用すると、不要な一時的なを作成しlistます)。list結果をソートする必要がない場合にのみ使用し、結果をソートする必要がある場合にのみ使用sortedします。
ShadowRanger

3

Pythonの魔法組み込み型

Pythonでは、このような複雑なケースを処理するのは非常に簡単で、Pythonの組み込みタイプによってのみ可能です。

やり方をお見せしましょう!

方法1:一般的なケース

リスト内の重複した要素を削除してもソート順を維持する方法(1行のコード

line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)

あなたは結果を得るでしょう

[1, 2, 3, 5, 6, 7, 8]

方法2:特殊なケース

TypeError: unhashable type: 'list'

ハッシュ化できない特別なケース(3行のコード

line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]

tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list

print (new_line)

結果が得られます:

[
  ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
  ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
  ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
  ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
  ['20.2929416861422', '-25.722717575124', '32.8500163147157']
]

タプルはハッシュ可能であり、リストとタプルの間でデータを簡単に変換できるため

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