डिफॉल्ट डिफॉल्ट का नेस्टेड निर्णय


129

क्या डिफॉल्ट करने का एक तरीका डिफॉल्ट का डिफॉल्ट भी है? (यानी अनंत-स्तरीय पुनरावर्ती डिफ़ॉल्ट निर्णय?)

मैं ऐसा करने में सक्षम होना चाहता हूं:

x = defaultdict(...stuff...)
x[0][1][0]
{}

तो, मैं कर सकता हूँ x = defaultdict(defaultdict), लेकिन यह केवल एक दूसरा स्तर है:

x[0]
{}
x[0][0]
KeyError: 0

ऐसे व्यंजन हैं जो ऐसा कर सकते हैं। लेकिन क्या यह सिर्फ सामान्य डिफ़ॉल्ट तर्क का उपयोग करके किया जा सकता है?

ध्यान दें कि यह पूछ रहा है कि अनंत-स्तर के पुनरावर्ती डिफॉल्ट कैसे करें, इसलिए यह पायथन के लिए अलग है : डिफॉल्ट का डिफाल्ट? , जो कि दो-स्तरीय डिफॉल्ट कैसे करना था।

मैं शायद सिर्फ बंच पैटर्न का उपयोग करके समाप्त हो जाऊंगा, लेकिन जब मुझे एहसास हुआ कि मुझे नहीं पता कि यह कैसे करना है, तो मुझे इसमें दिलचस्पी थी।



2
वास्तव में नहीं ... संकेत करने के लिए प्रश्न में जानकारी क्यों जोड़ा गया। हालांकि यह एक उपयोगी प्रश्न है।
कॉर्ली ब्रिगमैन

जवाबों:


168

स्तरों की एक मनमानी संख्या के लिए:

def rec_dd():
    return defaultdict(rec_dd)

>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}

बेशक आप एक लंबोदर के साथ भी ऐसा कर सकते हैं, लेकिन मुझे लगता है कि लंबोदर कम पठनीय हैं। किसी भी मामले में यह इस तरह दिखेगा:

rec_dd = lambda: defaultdict(rec_dd)

1
वास्तव में एक आदर्श उदाहरण, धन्यवाद। क्या आप इसे इस मामले में बढ़ा सकते हैं, कि डेटा को json से defaultdict के डिफॉल्ट में लोड किया गया है?
डेविड बेलोह्रद

4
एक नोट। यदि आप इस कोड का उपयोग करने की कोशिश कर रहे हैं तो अचार lambdaकाम नहीं करेगा।
वायाचेस्लाव कोंडरटुक 11

167

यहां अन्य उत्तर आपको बताते हैं कि कैसे बनाया जाए defaultdictजिसमें "असीम रूप से कई" शामिल हैं defaultdict, लेकिन वे यह संबोधित करने में विफल हैं कि मुझे क्या लगता है कि आपकी प्रारंभिक आवश्यकता हो सकती है जो कि केवल दो-गहराई वाले डिफ़ॉल्ट का होना था।

आप देख रहे होंगे:

defaultdict(lambda: defaultdict(dict))

जिन कारणों से आप इस निर्माण को पसंद कर सकते हैं वे हैं:

  • यह पुनरावर्ती समाधान से अधिक स्पष्ट है, और इसलिए पाठक के लिए अधिक समझने योग्य है।
  • यह defaultdictएक शब्दकोश के अलावा कुछ होने की "पत्ती" को सक्षम करता है , जैसे,: defaultdict(lambda: defaultdict(list))याdefaultdict(lambda: defaultdict(set))

3
defaultdict (लंबोदर: defaultdict (सूची)) सही फॉर्म?
युवराज लोगनाथन

ऊओप्स, हां, lambdaफॉर्म सही है - क्योंकि defaultdict(something)एक शब्दकोश जैसी वस्तु लौटाती है, लेकिन defaultdictएक कॉल करने की उम्मीद करती है! धन्यवाद!
क्रिस डब्ल्यू।

4
इसे एक और प्रश्न के संभावित डुप्लिकेट के रूप में चिह्नित किया गया ... लेकिन यह मेरा मूल प्रश्न नहीं था। मुझे पता था कि दो-स्तरीय डिफॉल्ट कैसे बनाया जाए; मुझे नहीं पता था कि इसे कैसे पुनरावर्ती बनाना है। यह उत्तर वास्तव में, stackoverflow.com/questions/5029934/… के
Corley Brigman

लैम्ब्डा एप्रोच का एक हिस्सा यह है कि इसे उत्पन्न करने वाली वस्तुओं को नहीं dict(result)
उठाया

54

ऐसा करने के लिए निफ्टी ट्रिक है:

tree = lambda: defaultdict(tree)

तब आप अपने xसाथ बना सकते हैं x = tree()


22

ब्रेनबर्न के समाधान के समान है, लेकिन इसमें चर का नाम treeदो बार नहीं है, इसलिए यह चर शब्दकोश में परिवर्तन के बाद भी काम करता है:

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))

तो फिर तुम हर नई बना सकते हैं xके साथ x = tree()


के लिए defसंस्करण, हम समारोह बंद गुंजाइश का उपयोग दोष जहां मौजूदा उदाहरणों अगर काम बंद से डेटा संरचना की रक्षा के लिए कर सकते हैं treeनाम पलटाव है। यह इस तरह दिख रहा है:

from collections import defaultdict

def tree():
    def the_tree():
        return defaultdict(the_tree)
    return the_tree()

4
मुझे इस बारे में सोचना होगा (यह थोड़ा अधिक जटिल है)। लेकिन मुझे लगता है कि आपकी बात यह है कि अगर x = ट्री () करते हैं, लेकिन तब कोई व्यक्ति बाद में आता है और ट्री = कोई नहीं, यह अभी भी काम करेगा, और यह नहीं होगा?
कॉर्ली ब्रिगमैन 20

11

मैं अधिक ओओपी-स्टाइल कार्यान्वयन का प्रस्ताव भी रखूंगा, जो अनंत घोंसले के शिकार होने के साथ-साथ ठीक से स्वरूपित भी करता है repr

class NestedDefaultDict(defaultdict):
    def __init__(self, *args, **kwargs):
        super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)

    def __repr__(self):
        return repr(dict(self))

उपयोग:

my_dict = NestedDefaultDict()
my_dict['a']['b'] = 1
my_dict['a']['c']['d'] = 2
my_dict['b']

print(my_dict)  # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}}

1
नीट! मैंने पस्चथ्रू को जोड़ा *argsऔर **kwargsजो इसे defaultdictकीवर्ड तर्कों के साथ एक तानाशाही बनाने के लिए अनुमति देता है । यह पारित करने के लिए उपयोगी है NestedDefaultDictमेंjson.load
सिपरियन Tomoiagă

0

यहाँ एक पुनरावर्ती कार्य को एक सामान्य डिक्टेट के लिए एक पुनरावर्ती डिफ़ॉल्ट रूप से परिवर्तित करना है

def defdict_to_dict(defdict, finaldict):
    # pass in an empty dict for finaldict
    for k, v in defdict.items():
        if isinstance(v, defaultdict):
            # new level created and that is the new value
            finaldict[k] = defdict_to_dict(v, {})
        else:
            finaldict[k] = v
    return finaldict

defdict_to_dict(my_rec_default_dict, {})

0

मैंने यहां एंड्रयू के जवाब पर आधारित किया । यदि आप किसी संदेश या डेटा को किसी मौजूदा डिक्टेटर से डेटा लोड करना चाहते हैं, तो इस उदाहरण को देखें:

def nested_defaultdict(existing=None, **kwargs):
    if existing is None:
        existing = {}
    if not isinstance(existing, dict):
        return existing
    existing = {key: nested_defaultdict(val) for key, val in existing.items()}
    return defaultdict(nested_defaultdict, existing, **kwargs)

https://gist.github.com/nucklehead/2d29628bb49115f3c30e78c071207775

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.