リスト内の重複を見つけて、それらを使用して別のリストを作成するにはどうすればよいですか?


437

Pythonリストで重複を見つけて、重複の別のリストを作成するにはどうすればよいですか?リストには整数のみが含まれます。



1
複製を1度行いますか、それとも再度表示するたびにしますか?
moooeeeep

私はこれがここでより多くの効率で答えられたと思います。stackoverflow.com/a/642919/1748045交差は組み込みの設定方法であり、必要なことを正確に実行する必要があります
Tom Smith

回答:


544

重複を削除するには、を使用しますset(a)。複製を印刷するには、次のようにします。

a = [1,2,3,2,1,5,6,5,5,5]

import collections
print([item for item, count in collections.Counter(a).items() if count > 1])

## [1, 2, 5]

これCounterは特に効率的ではなく(タイミング)、おそらくここではやりすぎです。setパフォーマンスが向上します。このコードは、ソースの順序で一意の要素のリストを計算します。

seen = set()
uniq = []
for x in a:
    if x not in seen:
        uniq.append(x)
        seen.add(x)

または、より簡潔に:

seen = set()
uniq = [x for x in a if x not in seen and not seen.add(x)]    

後者のスタイルはお勧めしません。何not seen.add(x)をしているのか明らかでないためです(set add()メソッドは常にを返すNoneため、が必要ですnot)。

ライブラリなしで複製された要素のリストを計算するには:

seen = {}
dupes = []

for x in a:
    if x not in seen:
        seen[x] = 1
    else:
        if seen[x] == 1:
            dupes.append(x)
        seen[x] += 1

リスト要素がハッシュ可能でない場合、セット/ディクテーションを使用できず、2次時間解に頼る必要があります(それぞれをそれぞれと比較します)。例えば:

a = [[1], [2], [3], [1], [5], [3]]

no_dupes = [x for n, x in enumerate(a) if x not in a[:n]]
print no_dupes # [[1], [2], [3], [5]]

dupes = [x for n, x in enumerate(a) if x in a[:n]]
print dupes # [[1], [3]]

2
@eric:たぶんそれはそうですO(n)、なぜならそれはリストを1回だけ反復し、設定された検索はだからO(1)です。
georg

3
@Hugo、重複のリストを表示するには、dupという新しいリストを作成し、elseステートメントを追加するだけです。例:dup = [] else: dup.append(x)
Chris Nielsen

4
@oxeimon:おそらくこれを取得しましたが、python 3で括弧付きで印刷されますprint()
Moberg

4
重複のみを取得するようにset()の回答を変換します。seen = set()その後dupe = set(x for x in a if x in seen or seen.add(x))
Ta946

2
Python 3.xの場合:print([item for item、count in collections.Counter(a).items()if count> 1])
kibitzforu

327
>>> l = [1,2,3,4,4,5,5,6,1]
>>> set([x for x in l if l.count(x) > 1])
set([1, 4, 5])

2
ジェネレータ内包表記の代わりにリスト内包表記を使用する理由はありますか?

64
実際、単純な解決策ですが、各count()がリストを繰り返し解析するため、複雑さが二乗されます。したがって、大きなリストには使用しないでください。
danuker、2015

4
@JohnJ、バブルソートもシンプルで機能します。それは私たちがそれを使うべきだという意味ではありません!
John La Rooy、2015

@JohnLaRooy実際には、並べ替えを行うためのより効率的な(そして簡単な)方法がほとんどないため、実際には使用しないことを意味します。
lostsoul29

1
@watsonic:「単純なスイッチ」では、一般的な場合に時間の複雑さを2次から2乗に減らすことができません。交換lしてset(l)ないので、最悪の場合の時間の複雑さを軽減し、唯一のものは、この答えを持つ大規模な効率の懸念に対処しないように。結局のところ、それほど単純ではなかったでしょう。つまり、これを行わないでください。
セシルカレー

82

アイテムが以前に表示されたかどうかに関係なく、カウントは必要ありません。適応その答えをこの問題に:

def list_duplicates(seq):
  seen = set()
  seen_add = seen.add
  # adds all elements it doesn't know yet to seen and all other to seen_twice
  seen_twice = set( x for x in seq if x in seen or seen_add(x) )
  # turn the set into a list (as requested)
  return list( seen_twice )

a = [1,2,3,2,1,5,6,5,5,5]
list_duplicates(a) # yields [1, 2, 5]

速度が問題になる場合に備えて、ここにいくつかのタイミングがあります:

# file: test.py
import collections

def thg435(l):
    return [x for x, y in collections.Counter(l).items() if y > 1]

def moooeeeep(l):
    seen = set()
    seen_add = seen.add
    # adds all elements it doesn't know yet to seen and all other to seen_twice
    seen_twice = set( x for x in l if x in seen or seen_add(x) )
    # turn the set into a list (as requested)
    return list( seen_twice )

def RiteshKumar(l):
    return list(set([x for x in l if l.count(x) > 1]))

def JohnLaRooy(L):
    seen = set()
    seen2 = set()
    seen_add = seen.add
    seen2_add = seen2.add
    for item in L:
        if item in seen:
            seen2_add(item)
        else:
            seen_add(item)
    return list(seen2)

l = [1,2,3,2,1,5,6,5,5,5]*100

これが結果です:(よくやった@JohnLaRooy!)

$ python -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
10000 loops, best of 3: 74.6 usec per loop
$ python -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
10000 loops, best of 3: 91.3 usec per loop
$ python -mtimeit -s 'import test' 'test.thg435(test.l)'
1000 loops, best of 3: 266 usec per loop
$ python -mtimeit -s 'import test' 'test.RiteshKumar(test.l)'
100 loops, best of 3: 8.35 msec per loop

興味深いことに、pypyを使用すると、タイミング自体の他に、ランキングもわずかに変化します。最も興味深いことに、カウンタベースのアプローチはpypyの最適化から大きな利益を得ますが、私が提案したメソッドキャッシングアプローチはほとんど効果がないようです。

$ pypy -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
100000 loops, best of 3: 17.8 usec per loop
$ pypy -mtimeit -s 'import test' 'test.thg435(test.l)'
10000 loops, best of 3: 23 usec per loop
$ pypy -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
10000 loops, best of 3: 39.3 usec per loop

明らかに、この影響は入力データの「重複」に関連しています。私はl = [random.randrange(1000000) for i in xrange(10000)]これらの結果を設定して取得しました:

$ pypy -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
1000 loops, best of 3: 495 usec per loop
$ pypy -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
1000 loops, best of 3: 499 usec per loop
$ pypy -mtimeit -s 'import test' 'test.thg435(test.l)'
1000 loops, best of 3: 1.68 msec per loop

6
好奇心旺盛です-seen_add = seen.addの目的は何ですか
ロブ

3
@Robこのようにして、以前に検索した関数を呼び出すだけです。それ以外の場合はadd、挿入が必要になるたびに、メンバー関数を検索(ディクショナリクエリ)する必要があります。
moooeeeep 2012

私自身のデータとIpythonの%timeitでチェックすると、メソッドはテストで最も速く見えますが、「最も遅い実行は、最も速い実行の4.34倍かかりました。これは、中間結果がキャッシュされていることを意味する可能性があります」
Joop

1
@moooeeeep、私はあなたが試すためにあなたのスクリプトに別のバージョンを追加しました:) pypyあなたがそれを手軽に持っていて、スピードを求めているなら、あなたも試してください。
John La Rooy、2015

@JohnLaRooyパフォーマンスが向上しました。興味深いことに、pypyを使用して結果を評価すると、カウンターベースのアプローチが大幅に向上します。
moooeeeep

42

使用できますiteration_utilities.duplicates

>>> from iteration_utilities import duplicates

>>> list(duplicates([1,1,2,1,2,3,4,2]))
[1, 1, 2, 2]

または、重複する各1つだけが必要な場合は、これを次と組み合わせることができますiteration_utilities.unique_everseen

>>> from iteration_utilities import unique_everseen

>>> list(unique_everseen(duplicates([1,1,2,1,2,3,4,2])))
[1, 2]

また、ハッシュ化できない要素も処理できます(ただし、パフォーマンスは犠牲になります)。

>>> list(duplicates([[1], [2], [1], [3], [1]]))
[[1], [1]]

>>> list(unique_everseen(duplicates([[1], [2], [1], [3], [1]])))
[[1]]

これは、他のアプローチのほんの一部しか処理できないものです。

ベンチマーク

ここで説明したアプローチのほとんど(すべてではない)を含む簡単なベンチマークを行いました。

最初のベンチマークには、一部のアプローチでは O(n**2)動作がある。

グラフでは、y軸は時間を表すため、値が小さいほど良いことを意味します。また、ログ-ログもプロットされるため、広範囲の値を視覚化できます。

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

O(n**2)アプローチを削除して、リスト内の50万要素まで別のベンチマークを行いました。

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

ご覧のとおり、このiteration_utilities.duplicatesアプローチは他のどのアプローチよりも高速で、チェーンunique_everseen(duplicates(...))より高速または同等に高速でした。

ここで注目すべきもう1つの興味深い点は、パンダのアプローチは小さなリストでは非常に遅いですが、長いリストでは簡単に競合できることです。

ただし、これらのベンチマークはほとんどのアプローチがほぼ同等に機能することを示しているため、どちらを使用しても問題ありません(O(n**2)ランタイムがあった3つを除く)。

from iteration_utilities import duplicates, unique_everseen
from collections import Counter
import pandas as pd
import itertools

def georg_counter(it):
    return [item for item, count in Counter(it).items() if count > 1]

def georg_set(it):
    seen = set()
    uniq = []
    for x in it:
        if x not in seen:
            uniq.append(x)
            seen.add(x)

def georg_set2(it):
    seen = set()
    return [x for x in it if x not in seen and not seen.add(x)]   

def georg_set3(it):
    seen = {}
    dupes = []

    for x in it:
        if x not in seen:
            seen[x] = 1
        else:
            if seen[x] == 1:
                dupes.append(x)
            seen[x] += 1

def RiteshKumar_count(l):
    return set([x for x in l if l.count(x) > 1])

def moooeeeep(seq):
    seen = set()
    seen_add = seen.add
    # adds all elements it doesn't know yet to seen and all other to seen_twice
    seen_twice = set( x for x in seq if x in seen or seen_add(x) )
    # turn the set into a list (as requested)
    return list( seen_twice )

def F1Rumors_implementation(c):
    a, b = itertools.tee(sorted(c))
    next(b, None)
    r = None
    for k, g in zip(a, b):
        if k != g: continue
        if k != r:
            yield k
            r = k

def F1Rumors(c):
    return list(F1Rumors_implementation(c))

def Edward(a):
    d = {}
    for elem in a:
        if elem in d:
            d[elem] += 1
        else:
            d[elem] = 1
    return [x for x, y in d.items() if y > 1]

def wordsmith(a):
    return pd.Series(a)[pd.Series(a).duplicated()].values

def NikhilPrabhu(li):
    li = li.copy()
    for x in set(li):
        li.remove(x)

    return list(set(li))

def firelynx(a):
    vc = pd.Series(a).value_counts()
    return vc[vc > 1].index.tolist()

def HenryDev(myList):
    newList = set()

    for i in myList:
        if myList.count(i) >= 2:
            newList.add(i)

    return list(newList)

def yota(number_lst):
    seen_set = set()
    duplicate_set = set(x for x in number_lst if x in seen_set or seen_set.add(x))
    return seen_set - duplicate_set

def IgorVishnevskiy(l):
    s=set(l)
    d=[]
    for x in l:
        if x in s:
            s.remove(x)
        else:
            d.append(x)
    return d

def it_duplicates(l):
    return list(duplicates(l))

def it_unique_duplicates(l):
    return list(unique_everseen(duplicates(l)))

ベンチマーク1

from simple_benchmark import benchmark
import random

funcs = [
    georg_counter, georg_set, georg_set2, georg_set3, RiteshKumar_count, moooeeeep, 
    F1Rumors, Edward, wordsmith, NikhilPrabhu, firelynx,
    HenryDev, yota, IgorVishnevskiy, it_duplicates, it_unique_duplicates
]

args = {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(2, 12)}

b = benchmark(funcs, args, 'list size')

b.plot()

ベンチマーク2

funcs = [
    georg_counter, georg_set, georg_set2, georg_set3, moooeeeep, 
    F1Rumors, Edward, wordsmith, firelynx,
    yota, IgorVishnevskiy, it_duplicates, it_unique_duplicates
]

args = {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(2, 20)}

b = benchmark(funcs, args, 'list size')
b.plot()

免責事項

1これは私が書いたサードパーティライブラリからのものですiteration_utilities


1
私はここで首を突き出し、PythonではなくCで作業を行うためにカスタムライブラリを作成することは、おそらく求められていた答えの精神ではありませんが、それは正当なアプローチです!私は答えの幅と結果のグラフィック表示が好きです-それらが収束しているのを見るのはとてもいいです、入力がさらに増えるにつれてそれらが交差するかどうか疑問に思います!質問:完全にランダムなリストではなく、ほとんどがソートされたリストの結果は何ですか?
F1の噂2018年

30

私は関連するものを調べているときにこの質問に出くわしました-なぜ誰もジェネレータベースのソリューションを提供しなかったのでしょうか?この問題を解決するには、次のようにします。

>>> print list(getDupes_9([1,2,3,2,1,5,6,5,5,5]))
[1, 2, 5]

私はスケーラビリティに関心があったので、小さなリストでうまく機能する素朴なアイテムなど、いくつかのアプローチをテストしましたが、リストが大きくなるにつれてひどくスケールしました(timeitを使用する方が良いでしょうが、これは例示です)。

私は比較のために@moooeeeepを含めました(これは印象的に高速です:入力リストが完全にランダムである場合は最速です)と、ほとんどソートされたリストで再び高速になるitertoolsアプローチ...ひどくそう、そして簡単です。注-並べ替え/ tee / zipアプローチは、大部分が順序付けられたリストの場合、私のマシンで一貫して最速で、moooeeeepは、シャッフルされたリストの場合で最速ですが、距離は異なる場合があります。

メリット

  • 同じコードを使用して「任意の」重複をテストするのは非常に簡単です

仮定

  • 重複は一度だけ報告されるべきです
  • 重複した注文を保持する必要はありません
  • 重複はリストのどこかにあるかもしれません

最速のソリューション、100万エントリ:

def getDupes(c):
        '''sort/tee/izip'''
        a, b = itertools.tee(sorted(c))
        next(b, None)
        r = None
        for k, g in itertools.izip(a, b):
            if k != g: continue
            if k != r:
                yield k
                r = k

テストされたアプローチ

import itertools
import time
import random

def getDupes_1(c):
    '''naive'''
    for i in xrange(0, len(c)):
        if c[i] in c[:i]:
            yield c[i]

def getDupes_2(c):
    '''set len change'''
    s = set()
    for i in c:
        l = len(s)
        s.add(i)
        if len(s) == l:
            yield i

def getDupes_3(c):
    '''in dict'''
    d = {}
    for i in c:
        if i in d:
            if d[i]:
                yield i
                d[i] = False
        else:
            d[i] = True

def getDupes_4(c):
    '''in set'''
    s,r = set(),set()
    for i in c:
        if i not in s:
            s.add(i)
        elif i not in r:
            r.add(i)
            yield i

def getDupes_5(c):
    '''sort/adjacent'''
    c = sorted(c)
    r = None
    for i in xrange(1, len(c)):
        if c[i] == c[i - 1]:
            if c[i] != r:
                yield c[i]
                r = c[i]

def getDupes_6(c):
    '''sort/groupby'''
    def multiple(x):
        try:
            x.next()
            x.next()
            return True
        except:
            return False
    for k, g in itertools.ifilter(lambda x: multiple(x[1]), itertools.groupby(sorted(c))):
        yield k

def getDupes_7(c):
    '''sort/zip'''
    c = sorted(c)
    r = None
    for k, g in zip(c[:-1],c[1:]):
        if k == g:
            if k != r:
                yield k
                r = k

def getDupes_8(c):
    '''sort/izip'''
    c = sorted(c)
    r = None
    for k, g in itertools.izip(c[:-1],c[1:]):
        if k == g:
            if k != r:
                yield k
                r = k

def getDupes_9(c):
    '''sort/tee/izip'''
    a, b = itertools.tee(sorted(c))
    next(b, None)
    r = None
    for k, g in itertools.izip(a, b):
        if k != g: continue
        if k != r:
            yield k
            r = k

def getDupes_a(l):
    '''moooeeeep'''
    seen = set()
    seen_add = seen.add
    # adds all elements it doesn't know yet to seen and all other to seen_twice
    for x in l:
        if x in seen or seen_add(x):
            yield x

def getDupes_b(x):
    '''iter*/sorted'''
    x = sorted(x)
    def _matches():
        for k,g in itertools.izip(x[:-1],x[1:]):
            if k == g:
                yield k
    for k, n in itertools.groupby(_matches()):
        yield k

def getDupes_c(a):
    '''pandas'''
    import pandas as pd
    vc = pd.Series(a).value_counts()
    i = vc[vc > 1].index
    for _ in i:
        yield _

def hasDupes(fn,c):
    try:
        if fn(c).next(): return True    # Found a dupe
    except StopIteration:
        pass
    return False

def getDupes(fn,c):
    return list(fn(c))

STABLE = True
if STABLE:
    print 'Finding FIRST then ALL duplicates, single dupe of "nth" placed element in 1m element array'
else:
    print 'Finding FIRST then ALL duplicates, single dupe of "n" included in randomised 1m element array'
for location in (50,250000,500000,750000,999999):
    for test in (getDupes_2, getDupes_3, getDupes_4, getDupes_5, getDupes_6,
                 getDupes_8, getDupes_9, getDupes_a, getDupes_b, getDupes_c):
        print 'Test %-15s:%10d - '%(test.__doc__ or test.__name__,location),
        deltas = []
        for FIRST in (True,False):
            for i in xrange(0, 5):
                c = range(0,1000000)
                if STABLE:
                    c[0] = location
                else:
                    c.append(location)
                    random.shuffle(c)
                start = time.time()
                if FIRST:
                    print '.' if location == test(c).next() else '!',
                else:
                    print '.' if [location] == list(test(c)) else '!',
                deltas.append(time.time()-start)
            print ' -- %0.3f  '%(sum(deltas)/len(deltas)),
        print
    print

「すべての重複」テストの結果は一貫しており、この配列で「最初の」重複、次に「すべての」重複が見つかりました。

Finding FIRST then ALL duplicates, single dupe of "nth" placed element in 1m element array
Test set len change :    500000 -  . . . . .  -- 0.264   . . . . .  -- 0.402  
Test in dict        :    500000 -  . . . . .  -- 0.163   . . . . .  -- 0.250  
Test in set         :    500000 -  . . . . .  -- 0.163   . . . . .  -- 0.249  
Test sort/adjacent  :    500000 -  . . . . .  -- 0.159   . . . . .  -- 0.229  
Test sort/groupby   :    500000 -  . . . . .  -- 0.860   . . . . .  -- 1.286  
Test sort/izip      :    500000 -  . . . . .  -- 0.165   . . . . .  -- 0.229  
Test sort/tee/izip  :    500000 -  . . . . .  -- 0.145   . . . . .  -- 0.206  *
Test moooeeeep      :    500000 -  . . . . .  -- 0.149   . . . . .  -- 0.232  
Test iter*/sorted   :    500000 -  . . . . .  -- 0.160   . . . . .  -- 0.221  
Test pandas         :    500000 -  . . . . .  -- 0.493   . . . . .  -- 0.499  

リストが最初にシャッフルされると、並べ替えの価格が明らかになります-効率が著しく低下し、@ moooeeeepアプローチが支配的です。

Finding FIRST then ALL duplicates, single dupe of "n" included in randomised 1m element array
Test set len change :    500000 -  . . . . .  -- 0.321   . . . . .  -- 0.473  
Test in dict        :    500000 -  . . . . .  -- 0.285   . . . . .  -- 0.360  
Test in set         :    500000 -  . . . . .  -- 0.309   . . . . .  -- 0.365  
Test sort/adjacent  :    500000 -  . . . . .  -- 0.756   . . . . .  -- 0.823  
Test sort/groupby   :    500000 -  . . . . .  -- 1.459   . . . . .  -- 1.896  
Test sort/izip      :    500000 -  . . . . .  -- 0.786   . . . . .  -- 0.845  
Test sort/tee/izip  :    500000 -  . . . . .  -- 0.743   . . . . .  -- 0.804  
Test moooeeeep      :    500000 -  . . . . .  -- 0.234   . . . . .  -- 0.311  *
Test iter*/sorted   :    500000 -  . . . . .  -- 0.776   . . . . .  -- 0.840  
Test pandas         :    500000 -  . . . . .  -- 0.539   . . . . .  -- 0.540  

@moooeeeep-ifilter / izip / teeアプローチについてのあなたの見解に興味を持ってください。
F1の噂2015

1
この答えは信じられないほど良いです。それを必要とする人にとって非常に役立つ説明とテストのためのより多くのポイントがなかったと私は理解していません。
dlewin 2015

1
pythonのソートは、1つのアイテムのみが故障している場合はO(n)です。あなたはそれrandom.shuffle(c)を説明するべきです。さらに、変更されていないスクリプトを実行した場合(まったく異なる順序)にも結果を再現できないため、CPUにも依存している可能性があります。
John La Rooy、2015

@ John-La-Rooyに感謝します。CPU/ローカルマシンでの鋭敏な観察が影響力を持っているため、アイテムYYMVを修正する必要があります。用いたO(n)をソート故意た:良いにおける唯一の重複がある場合、重複要素が異なる位置に挿入されているが、具体的なアプローチの影響を確認するために、これらと位置を(リストの先頭)または不良(リストの終わり)アプローチ。私はランダムなリスト-例えば、random.shuffle-を検討しましたが、もっと多くの実行をした場合にのみそれが賢明であると決めました!複数のラン/シャッフルの同等物を返却してベンチマークし、影響を確認する必要があります。
F1Rumors 2015

@firelynx pandasアプローチを含め、完全に並べ替えられたリストと並べ替えられたリストで実行するように修正されました。Pythonが使用されるネイティブtimsortがあるためである邪悪な結果までそのシェイク-主にデータをソート(最良の場合)とシャッフルリストはその最悪のシナリオある上に高速。
F1Rumors

13

パンダを使用する:

>>> import pandas as pd
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> pd.Series(a)[pd.Series(a).duplicated()].values
array([1, 3, 3])

10

collections.CounterはPython 2.7で新しく追加されました。


Python 2.5.4 (r254:67916, May 31 2010, 15:03:39) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
a = [1,2,3,2,1,5,6,5,5,5]
import collections
print [x for x, y in collections.Counter(a).items() if y > 1]
Type "help", "copyright", "credits" or "license" for more information.
  File "", line 1, in 
AttributeError: 'module' object has no attribute 'Counter'
>>> 

以前のバージョンでは、代わりに従来の辞書を使用できます:

a = [1,2,3,2,1,5,6,5,5,5]
d = {}
for elem in a:
    if elem in d:
        d[elem] += 1
    else:
        d[elem] = 1

print [x for x, y in d.items() if y > 1]

9

ここにきちんと簡潔な解決策があります-

for x in set(li):
    li.remove(x)

li = list(set(li))

ただし、元のリストは失われます。これは、コンテンツを別のリストにコピーすることで修正できます-temp = li [:]
Nikhil Prabhu

3
これは大きなリストではかなり厄介な作業です。リストから要素を削除するのは非常にコストがかかります。
F1の噂2017

7

リストに変換せずに、おそらく最も簡単な方法は以下のようなものになります。 これは、面接でセットを使用しないように依頼するときに役立つ場合があります。

a=[1,2,3,3,3]
dup=[]
for each in a:
  if each not in dup:
    dup.append(each)
print(dup)

=======それ以外の場合は、一意の値と重複する値の2つの個別のリストを取得する

a=[1,2,3,3,3]
uniques=[]
dups=[]

for each in a:
  if each not in uniques:
    uniques.append(each)
  else:
    dups.append(each)
print("Unique values are below:")
print(uniques)
print("Duplicate values are below:")
print(dups)

1
ただし、これはa(または元のリスト)の複製のリストにはなりませんが、これはa(または元のリスト)の一意の要素すべてのリストになります。リスト「dup」の作成が完了したら、誰かはどうしますか?
gameCoder95 2018年

6

私はパンダをよく使うので、私はパンダでこれを行います

import pandas as pd
a = [1,2,3,3,3,4,5,6,6,7]
vc = pd.Series(a).value_counts()
vc[vc > 1].index.tolist()

与える

[3,6]

おそらくあまり効率的ではありませんが、他の多くの回答よりもコードが少ないので、私は貢献すると思いました


3
パンダには組み込みの重複機能が含まれていることにも注意してください pda = pd.Series(a) print list(pda[pda.duplicated()])
Len Blokken

6

受け入れられた回答の3番目の例は、誤った回答を示し、重複を試みません。ここに正しいバージョンがあります:

number_lst = [1, 1, 2, 3, 5, ...]

seen_set = set()
duplicate_set = set(x for x in number_lst if x in seen_set or seen_set.add(x))
unique_set = seen_set - duplicate_set

6

出現回数をチェックしてリストの各要素をループし、それらをセットに追加して重複を出力するのはどうでしょう。これが誰かを助けることを願っています。

myList  = [2 ,4 , 6, 8, 4, 6, 12];
newList = set()

for i in myList:
    if myList.count(i) >= 2:
        newList.add(i)

print(list(newList))
## [4 , 6]

5

itertools.groupby重複しているすべてのアイテムを見つけるために使用できます。

from itertools import groupby

myList  = [2, 4, 6, 8, 4, 6, 12]
# when the list is sorted, groupby groups by consecutive elements which are similar
for x, y in groupby(sorted(myList)):
    #  list(y) returns all the occurences of item x
    if len(list(y)) > 1:
        print x  

出力は次のようになります。

4
6

1
またはもっと簡潔に:dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
frnhr

5

リスト内の重複を見つける最も効果的な方法は次のとおりです。

from collections import Counter

def duplicates(values):
    dups = Counter(values) - Counter(set(values))
    return list(dups.keys())

print(duplicates([1,2,3,6,5,2]))

それはCounterすべての要素とすべてのユニークな要素を使用します。最初のものを2番目のもので引くと、重複のみが除外されます。


4

少し遅れますが、一部の人には役立つかもしれません。大まかなリストの場合、これは私にとってはうまくいったことがわかりました。

l=[1,2,3,5,4,1,3,1]
s=set(l)
d=[]
for x in l:
    if x in s:
        s.remove(x)
    else:
        d.append(x)
d
[1,3,1]

すべての重複を表示し、順序を保持します。


3

Pythonで1回の繰り返しで重複を見つける非常にシンプルで迅速な方法は次のとおりです。

testList = ['red', 'blue', 'red', 'green', 'blue', 'blue']

testListDict = {}

for item in testList:
  try:
    testListDict[item] += 1
  except:
    testListDict[item] = 1

print testListDict

出力は次のようになります。

>>> print testListDict
{'blue': 3, 'green': 1, 'red': 2}

これと私のブログhttp://www.howtoprogramwithpython.com


3

私はこの議論にかなり遅れて入っています。とはいえ、この問題は1つのライナーで対処したいと思います。それがPythonの魅力だからです。別のリスト(または任意のコレクション)に重複を取得したいだけの場合は、以下のようにすることをお勧めします。「ターゲット」として呼び出すことができる重複したリストがあるとします

    target=[1,2,3,4,4,4,3,5,6,8,4,3]

複製を取得したい場合は、次のように1つのライナーを使用できます。

    duplicates=dict(set((x,target.count(x)) for x in filter(lambda rec : target.count(rec)>1,target)))

このコードは、重複したレコードをキーとしてカウントし、値としてカウントして、辞書 'duplicates'に入れます。

    {3: 3, 4: 4} #it saying 3 is repeated 3 times and 4 is 4 times

リストに重複のあるすべてのレコードだけが必要な場合は、はるかに短いコードを使用します。

    duplicates=filter(lambda rec : target.count(rec)>1,target)

出力は次のようになります。

    [3, 4, 4, 4, 3, 4, 3]

これはpython 2.7.x +バージョンで完全に機能します


3

独自のアルゴリズムを記述したり、ライブラリを使用したりする必要がない場合は、Python 3.8ワンライナー:

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

res = [(x, count) for x, g in groupby(sorted(l)) if (count := len(list(g))) > 1]

print(res)

アイテムとカウントを印刷します。

[(1, 2), (2, 2), (5, 4)]

groupbyグループ化関数を使用して、さまざまな方法でグループ化を定義し、Tuple必要に応じて追加のフィールドを返すことができます。

groupby 怠惰なので、遅すぎてはいけません。


2

他のいくつかのテスト。もちろんやります...

set([x for x in l if l.count(x) > 1])

...コストがかかりすぎます。次の最後のメソッドを使用すると、約500倍高速になります(配列が長いほど結果が良くなります)。

def dups_count_dict(l):
    d = {}

    for item in l:
        if item not in d:
            d[item] = 0

        d[item] += 1

    result_d = {key: val for key, val in d.iteritems() if val > 1}

    return result_d.keys()

ループは2つだけで、非常にコストのかかるl.count()操作はありません。

たとえば、メソッドを比較するコードは次のとおりです。コードは次のとおりです。出力は次のとおりです。

dups_count: 13.368s # this is a function which uses l.count()
dups_count_dict: 0.014s # this is a final best function (of the 3 functions)
dups_count_counter: 0.024s # collections.Counter

テストコード:

import numpy as np
from time import time
from collections import Counter

class TimerCounter(object):
    def __init__(self):
        self._time_sum = 0

    def start(self):
        self.time = time()

    def stop(self):
        self._time_sum += time() - self.time

    def get_time_sum(self):
        return self._time_sum


def dups_count(l):
    return set([x for x in l if l.count(x) > 1])


def dups_count_dict(l):
    d = {}

    for item in l:
        if item not in d:
            d[item] = 0

        d[item] += 1

    result_d = {key: val for key, val in d.iteritems() if val > 1}

    return result_d.keys()


def dups_counter(l):
    counter = Counter(l)    

    result_d = {key: val for key, val in counter.iteritems() if val > 1}

    return result_d.keys()



def gen_array():
    np.random.seed(17)
    return list(np.random.randint(0, 5000, 10000))


def assert_equal_results(*results):
    primary_result = results[0]
    other_results = results[1:]

    for other_result in other_results:
        assert set(primary_result) == set(other_result) and len(primary_result) == len(other_result)


if __name__ == '__main__':
    dups_count_time = TimerCounter()
    dups_count_dict_time = TimerCounter()
    dups_count_counter = TimerCounter()

    l = gen_array()

    for i in range(3):
        dups_count_time.start()
        result1 = dups_count(l)
        dups_count_time.stop()

        dups_count_dict_time.start()
        result2 = dups_count_dict(l)
        dups_count_dict_time.stop()

        dups_count_counter.start()
        result3 = dups_counter(l)
        dups_count_counter.stop()

        assert_equal_results(result1, result2, result3)

    print 'dups_count: %.3f' % dups_count_time.get_time_sum()
    print 'dups_count_dict: %.3f' % dups_count_dict_time.get_time_sum()
    print 'dups_count_counter: %.3f' % dups_count_counter.get_time_sum()

2

方法1:

list(set([val for idx, val in enumerate(input_list) if val in input_list[idx+1:]]))

説明: [idxのval、enumerate(input_list)のvalは、input_list [idx + 1:]のvalがリスト内包である場合、リストの現在の位置から同じ要素が存在する場合に、要素を返します。

例:input_list = [42,31,42,31,3,31,31,5,6,6,6,6,6,7,42]

リストの最初の要素42から始まり、インデックス0で、要素42がinput_list [1:]に存在するかどうかをチェックします(つまり、インデックス1からリストの最後まで)42がinput_list [1:]に存在するため、42を返します。

次に、インデックス1の次の要素31に移動し、要素31がinput_list [2:]に存在するかどうかを確認します(つまり、インデックス2からリストの最後まで)。31はinput_list [2:]に存在するため、 31を返します。

同様に、リスト内のすべての要素を処理し、繰り返し/重複した要素のみをリストに返します。

次に、リストに重複があるため、各重複の1つを選択する必要があります。つまり、重複の中から重複を削除します。これを行うには、set()という名前のpython組み込みを呼び出し、重複を削除します。

次に、リストではなくセットを残します。したがって、セットからリストに変換するには、型キャスト、list()を使用し、要素のセットをリストに変換します。

方法2:

def dupes(ilist):
    temp_list = [] # initially, empty temporary list
    dupe_list = [] # initially, empty duplicate list
    for each in ilist:
        if each in temp_list: # Found a Duplicate element
            if not each in dupe_list: # Avoid duplicate elements in dupe_list
                dupe_list.append(each) # Add duplicate element to dupe_list
        else: 
            temp_list.append(each) # Add a new (non-duplicate) to temp_list

    return dupe_list

説明: ここでは、最初に2つの空のリストを作成します。次に、リストのすべての要素をたどって、temp_list(最初は空)に存在するかどうかを確認します。temp_listにない場合は、appendメソッドを使用してtemp_listに追加ます

temp_listにすでに存在する場合は、リストの現在の要素が重複しているため、appendメソッドを使用してdupe_listに追加する必要があります


2
raw_list = [1,2,3,3,4,5,6,6,7,2,3,4,2,3,4,1,3,4,]

clean_list = list(set(raw_list))
duplicated_items = []

for item in raw_list:
    try:
        clean_list.remove(item)
    except ValueError:
        duplicated_items.append(item)


print(duplicated_items)
# [3, 6, 2, 3, 4, 2, 3, 4, 1, 3, 4]

基本的には、set(clean_list)に変換して重複を削除し、次にを反復処理し、クリーンリストからraw_listそれぞれを削除してitemで発生するようにしraw_listます。itemが見つからない場合、発生したValueError例外がキャッチitemされ、duplicated_itemsリストにます。

複製されたアイテムのインデックスが必要な場合はenumerate、リストだけを使用して、インデックスをいじってください。(for index, item in enumerate(raw_list):)高速であり、大規模なリスト(数千以上の要素など)に対して最適化されています


2

list.count()リスト内のメソッドを使用して、指定されたリストの重複要素を見つける

arr=[]
dup =[]
for i in range(int(input("Enter range of list: "))):
    arr.append(int(input("Enter Element in a list: ")))
for i in arr:
    if arr.count(i)>1 and i not in dup:
        dup.append(i)
print(dup)

count関数を使用してリスト内の重複する要素を見つける簡単な方法
Ravikiran D '11

2

ワンライナー、楽しみのために、単一のステートメントが必要な場合。

(lambda iterable: reduce(lambda (uniq, dup), item: (uniq, dup | {item}) if item in uniq else (uniq | {item}, dup), iterable, (set(), set())))(some_iterable)

1
list2 = [1, 2, 3, 4, 1, 2, 3]
lset = set()
[(lset.add(item), list2.append(item))
 for item in list2 if item not in lset]
print list(lset)

1

1行のソリューション:

set([i for i in list if sum([1 for a in list if a == i]) > 1])

1

ここにはたくさんの答えがありますが、これは比較的読みやすく、理解しやすいアプローチだと思います。

def get_duplicates(sorted_list):
    duplicates = []
    last = sorted_list[0]
    for x in sorted_list[1:]:
        if x == last:
            duplicates.append(x)
        last = x
    return set(duplicates)

ノート:

  • 重複カウントを保持したい場合は、下部にある「セット」へのキャストを削除して、完全なリストを取得します
  • ジェネレーターを使用する場合は、duplicates.append(x)yield xで置き換え、下部にreturnステートメントを置きます(キャストして後で設定できます)。

1

これは、dictを使用して各要素をブール値を持つキーとして保存し、重複するアイテムが既に生成されているかどうかを確認する高速ジェネレーターです。

すべての要素がハッシュ可能な型であるリストの場合:

def gen_dupes(array):
    unique = {}
    for value in array:
        if value in unique and unique[value]:
            unique[value] = False
            yield value
        else:
            unique[value] = True

array = [1, 2, 2, 3, 4, 1, 5, 2, 6, 6]
print(list(gen_dupes(array)))
# => [2, 1, 6]

リストを含む可能性のあるリストの場合:

def gen_dupes(array):
    unique = {}
    for value in array:
        is_list = False
        if type(value) is list:
            value = tuple(value)
            is_list = True

        if value in unique and unique[value]:
            unique[value] = False
            if is_list:
                value = list(value)

            yield value
        else:
            unique[value] = True

array = [1, 2, 2, [1, 2], 3, 4, [1, 2], 5, 2, 6, 6]
print(list(gen_dupes(array)))
# => [2, [1, 2], 6]

1
def removeduplicates(a):
  seen = set()

  for i in a:
    if i not in seen:
      seen.add(i)
  return seen 

print(removeduplicates([1,1,2,2]))

リクエストに応じてリストではなくセットを返します。セットには一意の要素のみが含まれるため、ifステートメントは実際には必要ありません。また、他のソリューションと比較した場合のソリューションの利点についても説明する必要があります。
クレメンス


0

私は他の方法を使用しないように自分自身に挑戦したので、これは私がそれをしなければならなかった方法です:

def dupList(oldlist):
    if type(oldlist)==type((2,2)):
        oldlist=[x for x in oldlist]
    newList=[]
    newList=newList+oldlist
    oldlist=oldlist
    forbidden=[]
    checkPoint=0
    for i in range(len(oldlist)):
        #print 'start i', i
        if i in forbidden:
            continue
        else:
            for j in range(len(oldlist)):
                #print 'start j', j
                if j in forbidden:
                    continue
                else:
                    #print 'after Else'
                    if i!=j: 
                        #print 'i,j', i,j
                        #print oldlist
                        #print newList
                        if oldlist[j]==oldlist[i]:
                            #print 'oldlist[i],oldlist[j]', oldlist[i],oldlist[j]
                            forbidden.append(j)
                            #print 'forbidden', forbidden
                            del newList[j-checkPoint]
                            #print newList
                            checkPoint=checkPoint+1
    return newList

したがって、サンプルは次のように機能します。

>>>a = [1,2,3,3,3,4,5,6,6,7]
>>>dupList(a)
[1, 2, 3, 4, 5, 6, 7]

3
これはOPが望んでいたものではありません。彼は、重複を削除したリストではなく、重複のリストを求めていました。重複を削除したリストを作成するには、をお勧めしduplist = list(set(a))ます。
zondo 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.