यदि तृतीय-पक्ष पैकेज का उपयोग करना ठीक होगा तो आप उपयोग कर सकते हैं iteration_utilities.unique_everseen
:
>>> from iteration_utilities import unique_everseen
>>> l = [{'a': 123}, {'b': 123}, {'a': 123}]
>>> list(unique_everseen(l))
[{'a': 123}, {'b': 123}]
यह मूल सूची के आदेश को संरक्षित करता है और यह भी एक धोखेबाज़ एल्गोरिथ्म पर वापस गिरने से शब्दकोशों जैसे अस्वाभाविक वस्तुओं को संभाल सकता है ( O(n*m)
जहां n
मूल सूची में तत्व हैं और मूल सूची m
में अद्वितीय तत्व हैं O(n)
)। यदि कुंजियाँ और मान दोनों ही उपलब्ध नहीं हैं, तो आप key
"अनूठेपन-परीक्षण" (ताकि यह काम करता है O(n)
) के लिए धोने योग्य आइटम बनाने के लिए उस फ़ंक्शन के तर्क का उपयोग कर सकें ।
एक शब्दकोश के मामले में (जो ऑर्डर के स्वतंत्र की तुलना करता है) आपको इसे किसी अन्य डेटा-संरचना में मैप करना होगा जो इस तरह की तुलना करता है, उदाहरण के लिए frozenset
:
>>> list(unique_everseen(l, key=lambda item: frozenset(item.items())))
[{'a': 123}, {'b': 123}]
ध्यान दें कि आपको एक सरल tuple
दृष्टिकोण (बिना छांटे) का उपयोग नहीं करना चाहिए क्योंकि समान शब्दकोशों के लिए आवश्यक रूप से समान आदेश नहीं है (यहां तक कि पायथन 3.7 में जहां सम्मिलन आदेश - पूर्ण आदेश नहीं - गारंटी है):
>>> d1 = {1: 1, 9: 9}
>>> d2 = {9: 9, 1: 1}
>>> d1 == d2
True
>>> tuple(d1.items()) == tuple(d2.items())
False
यदि कुंजी क्रमबद्ध नहीं हैं, तो भी टूपल को छांटना काम नहीं कर सकता है:
>>> d3 = {1: 1, 'a': 'a'}
>>> tuple(sorted(d3.items()))
TypeError: '<' not supported between instances of 'str' and 'int'
बेंचमार्क
मैंने सोचा कि यह देखने के लिए उपयोगी हो सकता है कि इन तरीकों का प्रदर्शन कैसे तुलना करता है, इसलिए मैंने एक छोटा बेंचमार्क किया। बेंचमार्क रेखांकन समय बनाम सूची-आकार की सूची पर आधारित है जिसमें कोई डुप्लिकेट नहीं है (जो मनमाने ढंग से चुना गया था, अगर मैं कुछ या बहुत सारे डुप्लिकेट जोड़ता हूं, तो रनटाइम महत्वपूर्ण रूप से नहीं बदलता है)। यह एक लॉग-लॉग प्लॉट है इसलिए पूरी रेंज कवर की गई है।
पूर्ण समय:
सबसे तेज़ दृष्टिकोण के सापेक्ष समय:
Thefourtheye से दूसरा दृष्टिकोण यहां सबसे तेज है। unique_everseen
साथ दृष्टिकोण key
समारोह, दूसरे स्थान पर है, लेकिन यह सबसे तेजी से दृष्टिकोण है कि बरकरार रखता है आदेश है। Jcollado और thefourtheye से अन्य दृष्टिकोण लगभग उपवास के रूप में हैं। unique_everseen
चाबी के बिना उपयोग करने वाला दृष्टिकोण और इमैनुएल और स्कॉर्पिल के समाधान लंबी सूचियों के लिए बहुत धीमी हैं और O(n*n)
इसके बजाय बहुत बुरा व्यवहार करते हैं O(n)
। stpk के दृष्टिकोण के साथ json
नहीं है, O(n*n)
लेकिन यह इसी तरह की तुलना में बहुत धीमी हैO(n)
दृष्टिकोण ।
बेंचमार्क को पुन: पेश करने के लिए कोड:
from simple_benchmark import benchmark
import json
from collections import OrderedDict
from iteration_utilities import unique_everseen
def jcollado_1(l):
return [dict(t) for t in {tuple(d.items()) for d in l}]
def jcollado_2(l):
seen = set()
new_l = []
for d in l:
t = tuple(d.items())
if t not in seen:
seen.add(t)
new_l.append(d)
return new_l
def Emmanuel(d):
return [i for n, i in enumerate(d) if i not in d[n + 1:]]
def Scorpil(a):
b = []
for i in range(0, len(a)):
if a[i] not in a[i+1:]:
b.append(a[i])
def stpk(X):
set_of_jsons = {json.dumps(d, sort_keys=True) for d in X}
return [json.loads(t) for t in set_of_jsons]
def thefourtheye_1(data):
return OrderedDict((frozenset(item.items()),item) for item in data).values()
def thefourtheye_2(data):
return {frozenset(item.items()):item for item in data}.values()
def iu_1(l):
return list(unique_everseen(l))
def iu_2(l):
return list(unique_everseen(l, key=lambda inner_dict: frozenset(inner_dict.items())))
funcs = (jcollado_1, Emmanuel, stpk, Scorpil, thefourtheye_1, thefourtheye_2, iu_1, jcollado_2, iu_2)
arguments = {2**i: [{'a': j} for j in range(2**i)] for i in range(2, 12)}
b = benchmark(funcs, arguments, 'list size')
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.style.use('ggplot')
mpl.rcParams['figure.figsize'] = '8, 6'
b.plot(relative_to=thefourtheye_2)
पूर्णता के लिए यहां केवल एक डुप्लिकेट वाली सूची के लिए समय है:
# this is the only change for the benchmark
arguments = {2**i: [{'a': 1} for j in range(2**i)] for i in range(2, 12)}
unique_everseen
बिना key
फंक्शन को छोड़कर टाइमिंग में बहुत बदलाव नहीं होता है , जो इस मामले में सबसे तेज समाधान है। हालाँकि यह उस समारोह के लिए केवल सबसे अच्छा मामला है (इसलिए प्रतिनिधि नहीं है) क्योंकि यह अनौपचारिक है क्योंकि यह रनटाइम सूची में अद्वितीय मानों की मात्रा पर निर्भर करता है: O(n*m)
जो इस मामले में सिर्फ 1 है और इस प्रकार यह चलता है O(n)
।
डिस्क्लेमर: मैं लेखक हूं iteration_utilities
।