كيف يمكنك إزالة التكرارات من القائمة مع الحفاظ على النظام؟

StackOverflow https://stackoverflow.com/questions/480214

سؤال

هل هناك خاصية مدمجة تزيل التكرارات من القائمة في بايثون، مع الحفاظ على النظام؟أعلم أنه يمكنني استخدام مجموعة لإزالة التكرارات، لكن هذا يدمر الترتيب الأصلي.أعلم أيضًا أنه يمكنني أن أتدحرج بنفسي مثل هذا:

def uniq(input):
  output = []
  for x in input:
    if x not in output:
      output.append(x)
  return output

(شكرا ل فك من أجل هذا عينة التعليمات البرمجية.)

لكنني أرغب في الاستفادة من لغة مدمجة أو لغة بايثونية أكثر إن أمكن.

سؤال ذو صلة: في بايثون، ما هي أسرع خوارزمية لإزالة التكرارات من القائمة بحيث تكون جميع العناصر فريدة من نوعها مع الحفاظ على النظام?

هل كانت مفيدة؟

المحلول

وهنا لديك بعض البدائل: http://www.peterbe.com/plog/uniqifiers- مؤشر

وأسرع واحد:

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

وماذا إسناد seen.add إلى seen_add بدلا من مجرد الدعوة seen.add؟ بايثون هي لغة ديناميكية، وحل seen.add كل التكرار هو أكثر تكلفة من حل متغير محلي. seen.add قد تغيرت بين التكرارات، ووقت التشغيل ليست ذكية بما يكفي لاستبعاد ذلك. لتشغيلها بطريقة آمنة، فإنه يجب أن تحقق الكائن في كل مرة.

إذا كنت تخطط لاستخدام هذه الوظيفة الكثير على نفس مجموعة البيانات، وربما سيكون أفضل حالا مع مجموعة مرتبة: <لأ href = "http://code.activestate.com/recipes/528878/" يختلط = "noreferrer"> http://code.activestate.com/recipes/528878/

O (1) الإدراج أو الحذف وأعضاء الاختيار في العملية.

و(صغير ملاحظة إضافية: seen.add() دوما بإرجاع None، وبالتالي فإن <م> or أعلاه ليس هناك سوى وسيلة لمحاولة تحديث مجموعة، وليس باعتبارها جزءا لا يتجزأ من اختبار منطقي)

نصائح أخرى

تحرير 2016

كما ريمون أشار, ، في بيثون 3.5+ حيث OrderedDict تم تنفيذه في لغة C، سيكون نهج فهم القائمة أبطأ من OrderedDict (ما لم تكن بحاجة بالفعل إلى القائمة في النهاية - وحتى في هذه الحالة، فقط إذا كان الإدخال قصيرًا جدًا).لذا فإن الحل الأفضل لـ 3.5+ هو OrderedDict.

تعديل مهم 2015

مثل @abarnert الملاحظات، more_itertools مكتبة (pip install more_itertools) يحتوي على unique_everseen الوظيفة التي تم تصميمها لحل هذه المشكلة دون أي غير قابل للقراءة (not seen.add) الطفرات في قائمة الفهم.وهذا أيضًا هو الحل الأسرع أيضًا:

>>> from  more_itertools import unique_everseen
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(unique_everseen(items))
[1, 2, 0, 3]

مجرد استيراد مكتبة واحد بسيط وبدون أي اختراقات.يأتي هذا من تطبيق وصفة itertools unique_everseen الذي يبدو مثل:

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

في بايثون 2.7+ ال المصطلح المشترك المقبول (الذي يعمل ولكنه غير محسّن للسرعة، سأستخدمه الآن unique_everseen) لهذا الاستخدامات collections.OrderedDict:

مدة العرض: على)

>>> from collections import OrderedDict
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(OrderedDict.fromkeys(items))
[1, 2, 0, 3]

هذا يبدو أجمل بكثير من:

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

ولا يستخدم اختراق قبيح:

not seen.add(x)

الذي يعتمد على حقيقة ذلك set.add هي طريقة موضعية تعود دائمًا None لذا not None يقيم ل True.

لاحظ مع ذلك أن حل الاختراق أسرع في السرعة الأولية على الرغم من أنه يتمتع بنفس تعقيد وقت التشغيل O(N).

في بيثون 2.7, ، الطريقة الجديدة لإزالة التكرارات من كائن قابل للتكرار مع الاحتفاظ بها بالترتيب الأصلي هي:

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

في بايثون 3.5, ، OrderedDict لديه تطبيق C.تُظهر توقيتاتي أن هذا هو الآن الأسرع والأقصر بين الأساليب المختلفة لـ Python 3.5.

في بايثون 3.6, ، أصبح الإملاء العادي منظمًا ومضغوطًا.(هذه الميزة متاحة لـ CPython وPyPy ولكنها قد لا تكون موجودة في تطبيقات أخرى).وهذا يمنحنا أسرع طريقة جديدة للخداع مع الحفاظ على النظام:

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

في بايثون 3.7, ، يتم ضمان الإملاء المنتظم لكلا الأمرين عبر جميع التطبيقات. لذا فإن الحل الأقصر والأسرع هو:

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

الرد على @max:بمجرد الانتقال إلى 3.6 أو 3.7 واستخدام الإملاء العادي بدلاً من ذلك OrderedDict, ، لا يمكنك حقًا التغلب على الأداء بأي طريقة أخرى.القاموس كثيف ويمكن تحويله بسهولة إلى قائمة دون أي حمل تقريبًا.تم تحديد حجم القائمة المستهدفة مسبقًا إلى len(d) الذي يحفظ كافة التغييرات التي تحدث في فهم القائمة.وأيضًا، نظرًا لأن قائمة المفاتيح الداخلية كثيفة، فإن نسخ المؤشرات يكون سريعًا تقريبًا مثل نسخة القائمة.

sequence = ['1', '2', '3', '3', '6', '4', '5', '6']
unique = []
[unique.append(item) for item in sequence if item not in unique]

وفريدة من نوعها → ['1', '2', '3', '6', '4', '5']

from itertools import groupby
[ key for key,_ in groupby(sortedList)]

القائمة لا يجب أن تكون كذلك مرتبة, فالشرط الكافي هو أن يتم تجميع القيم المتساوية معًا.

يحرر:لقد افترضت أن عبارة "الحفاظ على النظام" تعني أن القائمة مرتبة بالفعل.إذا لم يكن الأمر كذلك، فإن الحل من MizardX هو الحل الصحيح.

تحرير المجتمع:ومع ذلك، فهذه هي الطريقة الأكثر أناقة "لضغط العناصر المتتالية المكررة في عنصر واحد".

وليس لركلة حصان ميت (وهذا السؤال هو قديم جدا وبالفعل لديها الكثير من الإجابات جيدة)، ولكن هنا هو الحل باستخدام حيوانات الباندا التي هي سريعة جدا في كثير من الظروف وميت سهلة الاستعمال.

import pandas as pd

my_list = [0, 1, 2, 3, 4, 1, 2, 3, 5]

>>> pd.Series(my_list).drop_duplicates().tolist()
# Output:
# [0, 1, 2, 3, 4, 5]

واعتقد انه اذا كنت تريد الحفاظ على النظام،

يمكنك أن تجرب هذا:

list1 = ['b','c','d','b','c','a','a']    
list2 = list(set(list1))    
list2.sort(key=list1.index)    
print list2

OR بالمثل يمكنك القيام بذلك:

list1 = ['b','c','d','b','c','a','a']  
list2 = sorted(set(list1),key=list1.index)  
print list2 

يمكنك أيضا القيام بذلك:

list1 = ['b','c','d','b','c','a','a']    
list2 = []    
for i in list1:    
    if not i in list2:  
        list2.append(i)`    
print list2

ويمكن أيضا أن يكتب هذا:

list1 = ['b','c','d','b','c','a','a']    
list2 = []    
[list2.append(i) for i in list1 if not i in list2]    
print list2 

وفقط لإضافة آخر (performant للغاية) تنفيذ هذه الوظيفة من وحدة نمطية الخارجية <سوب> 1 : <وأ href = "https://iteration-utilities.readthedocs.io/en/latest/ ولدت / unique_everseen.html "يختلط =" noreferrer "> iteration_utilities.unique_everseen :

>>> from iteration_utilities import unique_everseen
>>> lst = [1,1,1,2,3,2,2,2,1,3,4]

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

تحليل التوقيت

وفعلت بعض التوقيتات (بيثون 3.6) وهذه تظهر أنها أسرع من جميع البدائل الأخرى اختبرت، بما في ذلك OrderedDict.fromkeys، f7 وmore_itertools.unique_everseen:

%matplotlib notebook

from iteration_utilities import unique_everseen
from collections import OrderedDict
from more_itertools import unique_everseen as mi_unique_everseen

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

def iteration_utilities_unique_everseen(seq):
    return list(unique_everseen(seq))

def more_itertools_unique_everseen(seq):
    return list(mi_unique_everseen(seq))

def odict(seq):
    return list(OrderedDict.fromkeys(seq))

from simple_benchmark import benchmark

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: list(range(2**i)) for i in range(1, 20)},
              'list size (no duplicates)')
b.plot()

وفقط للتأكد من أنني أيضا فعلت ذلك لاختبار مع تكرارات أكثر فقط لمعرفة ما اذا كان يحدث فرقا:

import random

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(1, 20)},
              'list size (lots of duplicates)')
b.plot()

واحدة تحتوي على قيمة واحدة فقط:

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: [1]*(2**i) for i in range(1, 20)},
              'list size (only duplicates)')
b.plot()

في كل من هذه الحالات وظيفة iteration_utilities.unique_everseen هو الأسرع (على جهاز الكمبيوتر الخاص بي).


وهذه الوظيفة iteration_utilities.unique_everseen يمكن أيضا التعامل مع القيم unhashable في المدخلات (ولكن مع أداء O(n*n) بدلا من أداء O(n) عندما تكون القيم هي hashable).

>>> lst = [{1}, {1}, {2}, {1}, {3}]

>>> list(unique_everseen(lst))
[{1}, {2}, {3}]

<سوب> 1 تنويه: أنا مؤلف تلك الحزمة

للحصول على إجابة أخرى متأخرة جدًا لسؤال آخر قديم جدًا:

ال itertools وصفات لديك وظيفة تقوم بذلك، وذلك باستخدام seen ضبط التقنية، ولكن:

  • يتعامل مع معيار key وظيفة.
  • لا يستخدم أي اختراقات غير لائقة.
  • تحسين الحلقة عن طريق الربط المسبق seen.add بدلاً من البحث عنه مرات N.(f7 يفعل هذا أيضًا، لكن بعض الإصدارات لا تفعل ذلك.)
  • يحسن الحلقة باستخدام ifilterfalse, ، لذلك ما عليك سوى تكرار العناصر الفريدة في بايثون، بدلاً من تكرارها جميعًا.(ما زلت تتكرر على كل منهم في الداخل ifilterfalse, ، بالطبع، ولكن هذا في لغة C، وأسرع بكثير.)

هل هو في الواقع أسرع من f7؟يعتمد ذلك على بياناتك، لذا سيتعين عليك اختبارها والتأكد من ذلك.إذا كنت تريد قائمة في النهاية، f7 يستخدم listcomp، ولا توجد طريقة للقيام بذلك هنا.(يمكنك مباشرة append بدلاً من yieldجي، أو يمكنك تغذية المولد في list وظيفة، ولكن لا يمكن لأي منهما أن يكون بنفس سرعة LIST_APPEND داخل listcomp.) على أي حال، عادة، لن يكون الضغط على بضعة ميكروثانية بنفس أهمية وجود وظيفة سهلة الفهم وقابلة لإعادة الاستخدام ومكتوبة بالفعل والتي لا لا تحتاج إلى DSU عندما تريد التزيين.

كما هو الحال مع جميع الوصفات، فهو متوفر أيضًا في more-iterools.

إذا كنت تريد فقط عدمkey الحالة، يمكنك تبسيطها على النحو التالي:

def unique(iterable):
    seen = set()
    seen_add = seen.add
    for element in itertools.ifilterfalse(seen.__contains__, iterable):
        seen_add(element)
        yield element

في <القوي> بيثون 3.7 و أعلاه، القواميس هي <وأ href = "https://mail.python.org/pipermail/python-dev/2017-December/151283.html" يختلط = " noreferrer "> مضمونة لنتذكر أجل الإدراج الرئيسي لها. الإجابة على يلخص هذا السؤال الحالة الراهنة للأمور.

والحل OrderedDict بالتالي يصبح عفا عليها الزمن وبدون أي بيانات استيراد نستطيع ببساطة المشكلة:

>>> lst = [1, 2, 1, 3, 3, 2, 4]
>>> list(dict.fromkeys(lst))
[1, 2, 3, 4]

لأي أنواع hashable (مثل قائمة من القوائم)، استنادا لMizardX:

def f7_noHash(seq)
    seen = set()
    return [ x for x in seq if str( x ) not in seen and not seen.add( str( x ) )]

والاقتراض فكرة متكررة المستخدمة في definining وظيفة nub هاسكل للقوائم، وهذا سيكون نهج العودية:

def unique(lst):
    return [] if lst==[] else [lst[0]] + unique(filter(lambda x: x!= lst[0], lst[1:]))

ومنها مثلا:

In [118]: unique([1,5,1,1,4,3,4])
Out[118]: [1, 5, 4, 3]

وحاولت ذلك لزراعة أحجام البيانات ورأى شبه الخطية الوقت التعقيد (لا نهائية، ولكن يشير هذا ينبغي أن يكون على ما يرام للبيانات العادية).

In [122]: %timeit unique(np.random.randint(5, size=(1)))
10000 loops, best of 3: 25.3 us per loop

In [123]: %timeit unique(np.random.randint(5, size=(10)))
10000 loops, best of 3: 42.9 us per loop

In [124]: %timeit unique(np.random.randint(5, size=(100)))
10000 loops, best of 3: 132 us per loop

In [125]: %timeit unique(np.random.randint(5, size=(1000)))
1000 loops, best of 3: 1.05 ms per loop

In [126]: %timeit unique(np.random.randint(5, size=(10000)))
100 loops, best of 3: 11 ms per loop

وأعتقد أيضا أنه من المثير للاهتمام أن هذا يمكن تعميمه بسهولة للتفرد من العمليات الأخرى. مثل هذا:

import operator
def unique(lst, cmp_op=operator.ne):
    return [] if lst==[] else [lst[0]] + unique(filter(lambda x: cmp_op(x, lst[0]), lst[1:]), cmp_op)

وعلى سبيل المثال، يمكن أن يمر في وظيفة يستخدم مفهوم التقريب إلى نفس صحيحا كما لو كانت "المساواة" لأغراض التفرد، مثل هذا:

def test_round(x,y):
    return round(x) != round(y)

وبعد ذلك فريدة من نوعها (some_list، test_round) من شأنه أن يوفر العناصر الفريدة القائمة حيث تفرد لم تعد تعني المساواة التقليدية (التي ينطوي عليها استخدام أي نوع من القائمة على مجموعة أو ديكت أساس مفتاح نهج لهذه المشكلة)، ولكن بدلا من ذلك من المفترض أن يستغرق سوى العنصر الأول الذي جولات إلى K لكل الممكن صحيح K أن العناصر قد تقريبها إلى، على سبيل المثال:

In [6]: unique([1.2, 5, 1.9, 1.1, 4.2, 3, 4.8], test_round)
Out[6]: [1.2, 5, 1.9, 4.2, 3]

و5 × أسرع تقليل البديل ولكن أكثر تطورا

>>> l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
>>> 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())
# use 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]
[5, 6, 1, 2, 3, 4]

والجواب MizardX ليعطي مجموعة جيدة من نهج متعددة.

وهذا هو ما خطرت لي أثناء التفكير بصوت عال:

mylist = [x for i,x in enumerate(mylist) if x not in mylist[i+1:]]

ويمكنك الرجوع إلى فهم القائمة كما يجري بناؤه من قبل رمز '_ [1].
على سبيل المثال، الدالة التالية فريدة من نوعها ifies قائمة بالعناصر دون تغيير ترتيبها عن طريق الرجوع الفهم قائمتها.

def unique(my_list): 
    return [x for x in my_list if x not in locals()['_[1]']]

وعرض توضيحي:

l1 = [1, 2, 3, 4, 1, 2, 3, 4, 5]
l2 = [x for x in l1 if x not in locals()['_[1]']]
print l2

وإخراج:

[1, 2, 3, 4, 5]

هل يمكن أن تفعل نوعا من القبيح قائمة الفهم الإختراق.

[l[i] for i in range(len(l)) if l.index(l[i]) == i]

ونهج فعال نسبيا مع _sorted_ لصفائف numpy:

b = np.array([1,3,3, 8, 12, 12,12])    
numpy.hstack([b[0], [x[0] for x in zip(b[1:], b[:-1]) if x[0]!=x[1]]])

والمخرجات:

array([ 1,  3,  8, 12])
l = [1,2,2,3,3,...]
n = []
n.extend(ele for ele in l if ele not in set(n))

وتعبير مولد يستخدم O (1) بحث عن مجموعة لتحديد ما إذا كان إدراج أو عدم إدراج عنصر في القائمة الجديدة.

وهناك حل العودية بسيط:

def uniquefy_list(a):
    return uniquefy_list(a[1:]) if a[0] in a[1:] else [a[0]]+uniquefy_list(a[1:]) if len(a)>1 else [a[0]]

إذا كنت تحتاج بطانة واحدة ثم ربما هذا من شأنه أن يساعد:

reduce(lambda x, y: x + y if y[0] not in x else x, map(lambda x: [x],lst))

... يجب أن تعمل ولكن تصحيح لي إذا كنت مخطئا

إذا كنت عادة استخدام pandas ، ويفضل الجمال على الأداء، ثم النظر في المدمج في وظيفة pandas.Series.drop_duplicates :

    import pandas as pd
    import numpy as np

    uniquifier = lambda alist: pd.Series(alist).drop_duplicates().tolist()

    # from the chosen answer 
    def f7(seq):
        seen = set()
        seen_add = seen.add
        return [ x for x in seq if not (x in seen or seen_add(x))]

    alist = np.random.randint(low=0, high=1000, size=10000).tolist()

    print uniquifier(alist) == f7(alist)  # True

والتوقيت:

    In [104]: %timeit f7(alist)
    1000 loops, best of 3: 1.3 ms per loop
    In [110]: %timeit uniquifier(alist)
    100 loops, best of 3: 4.39 ms per loop

وهذا سوف الحفاظ على النظام وتشغيله في (ن) وقت O. في الأساس والفكرة هي لخلق ثقب في أي مكان هناك مكررة وجدت واغراقها إلى أسفل. يجعل من استخدام القراءة والكتابة المؤشر. كلما نسخة مكررة وجدت فقط التقدم مؤشر القراءة والكتابة مؤشر يبقى على إدخال مكرر الكتابة فوقه.

def deduplicate(l):
    count = {}
    (read,write) = (0,0)
    while read < len(l):
        if l[read] in count:
            read += 1
            continue
        count[l[read]] = True
        l[write] = l[read]
        read += 1
        write += 1
    return l[0:write]

وهناك حل دون استخدام وحدات المستوردة أو مجموعات:

text = "ask not what your country can do for you ask what you can do for your country"
sentence = text.split(" ")
noduplicates = [(sentence[i]) for i in range (0,len(sentence)) if sentence[i] not in sentence[:i]]
print(noduplicates)

ويعطي الإخراج:

['ask', 'not', 'what', 'your', 'country', 'can', 'do', 'for', 'you']

هناك طريقة في مكان

وهذا الأسلوب هو من الدرجة الثانية، وذلك لأن لدينا بحث الخطي في قائمة لكل عنصر من عناصر القائمة (لذلك علينا أن نضيف تكلفة إعادة ترتيب القائمة بسبب del ق).

وقال ذلك، فمن الممكن أن تعمل في مكان إذا انطلقنا من نهاية القائمة والمضي قدما نحو أصل إزالة كل مصطلح موجود في قائمة فرعية في حقها

وهذه الفكرة في التعليمات البرمجية هو ببساطة

for i in range(len(l)-1,0,-1): 
    if l[i] in l[:i]: del l[i] 

وهناك اختبار بسيط لتنفيذ

In [91]: from random import randint, seed                                                                                            
In [92]: seed('20080808') ; l = [randint(1,6) for _ in range(12)] # Beijing Olympics                                                                 
In [93]: for i in range(len(l)-1,0,-1): 
    ...:     print(l) 
    ...:     print(i, l[i], l[:i], end='') 
    ...:     if l[i] in l[:i]: 
    ...:          print( ': remove', l[i]) 
    ...:          del l[i] 
    ...:     else: 
    ...:          print() 
    ...: print(l)
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5, 2]
11 2 [6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5]: remove 2
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5]
10 5 [6, 5, 1, 4, 6, 1, 6, 2, 2, 4]: remove 5
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4]
9 4 [6, 5, 1, 4, 6, 1, 6, 2, 2]: remove 4
[6, 5, 1, 4, 6, 1, 6, 2, 2]
8 2 [6, 5, 1, 4, 6, 1, 6, 2]: remove 2
[6, 5, 1, 4, 6, 1, 6, 2]
7 2 [6, 5, 1, 4, 6, 1, 6]
[6, 5, 1, 4, 6, 1, 6, 2]
6 6 [6, 5, 1, 4, 6, 1]: remove 6
[6, 5, 1, 4, 6, 1, 2]
5 1 [6, 5, 1, 4, 6]: remove 1
[6, 5, 1, 4, 6, 2]
4 6 [6, 5, 1, 4]: remove 6
[6, 5, 1, 4, 2]
3 4 [6, 5, 1]
[6, 5, 1, 4, 2]
2 1 [6, 5]
[6, 5, 1, 4, 2]
1 5 [6]
[6, 5, 1, 4, 2]

In [94]:                                                                                                                             

والقضاء على قيم مكررة في تسلسل، ولكن الحفاظ على ترتيب العناصر المتبقية. استخدام وظيفة عامة الغرض المولد.

# for hashable sequence
def remove_duplicates(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)

a = [1, 5, 2, 1, 9, 1, 5, 10]
list(remove_duplicates(a))
# [1, 5, 2, 9, 10]



# for unhashable sequence
def remove_duplicates(items, key=None):
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(val)

a = [ {'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
list(remove_duplicates(a, key=lambda d: (d['x'],d['y'])))
# [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]

ونهج ZMK ويستخدم الفهم القائمة وهو سريع جدا، ولكن يبقى أمر طبيعي. لتطبيق إلى الحالة سلاسل حساسة يمكن تعديلها بسهولة. هذا يحافظ أيضا على الدعوى الأصلية.

def DelDupes(aseq) :
    seen = set()
    return [x for x in aseq if (x.lower() not in seen) and (not seen.add(x.lower()))]

وظائف مرتبطة ارتباطا وثيقا هي:

def HasDupes(aseq) :
    s = set()
    return any(((x.lower() in s) or s.add(x.lower())) for x in aseq)

def GetDupes(aseq) :
    s = set()
    return set(x for x in aseq if ((x.lower() in s) or s.add(x.lower())))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top