अंतर सेट करते समय अंतिम तत्व की अनदेखी करने का पायथोनिक तरीका


11

मान लें कि मेरे पास दो set()s हैं:

a = {('1', '2', '3', 'a'), ('1', '2', '4', 'a'), ('1', '2', '5', 'b')}
b = {('1', '2', '3', 'b'), ('1', '2', '4', 'b'), ('1', '2', '6', 'b')}

अब, मैं जो करना चाहता हूं वह है सेट अंतर को ढूंढना b \ aलेकिन हर टपल से अंतिम तत्व को अनदेखा करना। तो यह ऐसा कुछ करने जैसा है:

a = {('1', '2', '3'), ('1', '2', '4'), ('1', '2', '5')}
b = {('1', '2', '3'), ('1', '2', '4'), ('1', '2', '6')}

In[1]: b - a
Out[1]: {('1', '2', '6')}

अपेक्षित उत्पादन:

b \ a = {('1', '2', '6', 'b')}

क्या प्रत्येक सेट पर मैन्युअल रूप से पुनरावृति करने और प्रत्येक के खिलाफ जांच करने के बिना इसे प्राप्त करने का कोई स्पष्ट / पायथोनिक तरीका है tuple[:3]?


3
मेरा प्रारंभिक विचार उन्हें कक्षाएं बनाता है, तुलना ऑपरेटर को परिभाषित करता है
केनी ओस्ट्रोम

2
उपवर्ग setऔर अंतर ऑपरेशन को अधिलेखित करें। कोई भी आउट-ऑफ-द-बॉक्स समाधान नहीं है जो मुझे पता है और मुझे संदेह है कि कोई मौजूद है।
ईव। कोउनिस

सेट के लिए कोई "कुंजी = ..." या कुछ समान नहीं है (जैसे (..))। ट्यूपल्स अपरिवर्तनीय और हस्शेबल हैं और उनकी हैश के आधार पर तुलना की जाती है। एक तत्व को हटाने से हैश शून्य हो जाएगा। तो नहीं - संभव नहीं है। यदि आपको मूल्य की आवश्यकता नहीं है तो आप 3-भाग सेट बना सकते हैं:aa = { t[:3] for t in a }
पैट्रिक आर्टनर

2
@ AK47 दो सेट S और T के बीच का अंतर (सेट) S and T लिखा जाता है, और इसका अर्थ है वह सेट जिसमें S के तत्व होते हैं जो T के तत्व नहीं होते हैं: x∈S ⟺ T⟺x∈S∧x∉T
ग्रेजेडेनु एलेक्स।

उपवर्ग tupleऔर अंतर ऑपरेटर ओवरराइड
Pynchia

जवाबों:


10

यहाँ बताया गया है कि आप एक सामान्य सामान्य हैशिंग व्यवहार को ओवरराइड करने के लिए अपनी कक्षा कैसे लिख सकते हैं:

a_data = [('1', '2', '3', 'a'), ('1', '2', '4', 'a'), ('1', '2', '5', 'b')]
b_data = [('1', '2', '3', 'b'), ('1', '2', '4', 'b'), ('1', '2', '6', 'b')]

class HashableIgnoresLastElement(tuple):
    def __eq__(self, other):
        return self[:-1] == other[:-1]

    def __hash__(self):
        return hash(self[:-1])

a = set(map(HashableIgnoresLastElement, a_data))
b = set(map(HashableIgnoresLastElement, b_data))

print(b - a)

आउटपुट के साथ

{('1', '2', '6', 'b')}

ट्यूपल्स के व्यवहार को सेट करने के तरीके को संशोधित करने के लिए, हमें उस तरीके को संशोधित करना होगा जिस तरह से ट्यूपल्स हैशेड हैं।

से यहाँ ,

यदि कोई हैश वैल्यू है, तो कोई ऑब्जेक्ट हैवी है, जो उसके जीवनकाल के दौरान कभी नहीं बदलता है (इसे एक __hash__()विधि की आवश्यकता होती है), और इसकी तुलना अन्य वस्तुओं से की जा सकती है (इसे एक __eq__()विधि की आवश्यकता है )। हेशिबल ऑब्जेक्ट जो समान की तुलना करते हैं, उनका समान हैश मान होना चाहिए।

Hashability एक शब्दकोश कुंजी और एक सेट सदस्य के रूप में एक वस्तु को प्रयोग करने योग्य बनाता है, क्योंकि ये डेटा संरचनाएं आंतरिक रूप से हैश मान का उपयोग करती हैं।

इसलिए हैशिंग को अंतिम तत्व को अनदेखा करने के लिए, हमें उचित तरीकों __eq__और __hash__उचित तरीके से ओवरलोड करना होगा । इसका अंत इतना कठिन नहीं है क्योंकि हमें बस इतना करना है कि पिछले तत्व को खत्म कर दिया जाए और फिर एक सामान्य तरीके से उचित तरीकों को सौंप दिया जाए tuple

आगे की पढाई:


1
बहुत साफ़! क्या आप यह भी बता सकते हैं कि यह कैसे काम करता है? यह उन लोगों के लिए लायक हो सकता है जो इस समाधान के माध्यम से पढ़ेंगे।
ग्रेजेडेनु एलेक्स।

@GrajdeanuAlex। मैंने एक छोटा स्पष्टीकरण जोड़ा है :)। वास्तव में यह बस ओवरलोडिंग के ऑपरेटर के टुकड़ों और टुकड़ों का संयोजन है और पाइथन में हैशिंग कैसे काम करता है।
इजाक वैन

2

यहाँ एक दृष्टिकोण को परिभाषित करने aऔर bसेट के बजाय सूचियों के साथ है, क्योंकि यह मुझे लगता है कि सबसे सीधा आगे समाधान अनुक्रमण का मतलब है b:

a = [('1', '2', '3', 'a'), ('1', '2', '4', 'a'), ('1', '2', '5', 'b')]
b = [('1', '2', '3', 'b'), ('1', '2', '4', 'b'), ('1', '2', '6', 'b')]

# reconstruct the sets of tuples removing the last elements
a_ = {tuple(t) for *t, _ in a}
b_ = [tuple(t) for *t, _ in b]

# index b based on whether an element in a_
[b[ix] for ix, j in enumerate(b_) if j not in a_]
# [('1', '2', '6', 'b')]

1
यदि मैं गलत नहीं हूँ तो यह O (n) है, क्योंकि मैं लुकअप के लिए एक सेट का उपयोग करता हूँ। हालांकि मुझे लगता है कि Izaak वैन Dongen के जवाब और अधिक सुरुचिपूर्ण @konrad है
yatu

1
आप पूरी तरह से सही हैं, एक सूची के (और एन्यूमरेशन ओवर) के उपयोग ने मुझे फेंक दिया लेकिन निश्चित रूप से एक सेट अंतर को भी पहले सेट पर पुनरावृति करने की आवश्यकता है।
कोनराड रुडोल्फ

1

सेट ठीक काम करता है। यह आपका डेटा है जो सही काम नहीं करता है। यदि वे अलग दिखते हैं, लेकिन वे वास्तव में एक ही हैं, तो एक डेटा प्रकार को परिभाषित करें जो आपके जैसा व्यवहार करता है। फिर अपने आप ही शानदार काम करता है।

class thing:
    def __init__(self, a, b, c, d):
        self.a, self.b, self.c, self.d = a, b, c, d

    def __repr__(self):
        return (str((self.a, self.b, self.c, self.d)))

    def __hash__(self):
        return hash((self.a, self.b, self.c))

    def __eq__(self, other):
        return self.a == other.a and self.b == other.b and self.c == other.c       

a = {thing('1', '2', '3', 'a'), thing('1', '2', '4', 'a'), thing('1', '2', '5', 'b')}
b = {thing('1', '2', '3', 'b'), thing('1', '2', '4', 'b'), thing('1', '2', '6', 'b')}
print (b - a)

{('1', '2', '6', 'बी')}


3
आपने परिभाषित किया __repr__और __hash__टुपल्स के संदर्भ में, लेकिन नहीं __eq__। क्या यहां ट्यूल का उपयोग करना भी कम नहीं होगा? वास्तव में, आप यहां कोडिंग को और __hash__छोटा कर सकते हैं और आगे कोड को छोटा कर सकते हैं ।
कोनराड रुडोल्फ

ऐ, बस टंकण को ​​टालना सवाल के अनुसार एक बड़ा सुधार था।
केनी ओस्ट्रोम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.