পাইথন: ডিফল্টডিক্টের ডিফল্টডিক্ট?


322

defaultdict(defaultdict(int))নিম্নলিখিত কোডটি কাজ করার জন্য কোনও উপায় আছে কি ?

for x in stuff:
    d[x.a][x.b] += x.c_int

dচাহিদা উপর নির্ভর করে, অ্যাড-হক নির্মিত হবে x.aএবং x.bউপাদান।

আমি ব্যবহার করতে পারি:

for x in stuff:
    d[x.a,x.b] += x.c_int

তবে আমি ব্যবহার করতে সক্ষম হব না:

d.keys()
d[x.a].keys()

উত্তর:


570

হ্যাঁ এর মতো:

defaultdict(lambda: defaultdict(int))

আপনি অস্তিত্ব নেই এমন কোনও কী অ্যাক্সেস করার চেষ্টা করার সময় একটি defaultdict(এই ক্ষেত্রে lambda: defaultdict(int)) এর আর্গুমেন্ট কল করা হবে। এর রিটার্ন মানটি এই কীটির নতুন মান হিসাবে সেট করা হবে, যার অর্থ আমাদের ক্ষেত্রে এর মান d[Key_doesnt_exist]হবে defaultdict(int)

আপনি যদি এই সর্বশেষ ডিফল্টডিক্টিক্ট থেকে কোনও কীটি অ্যাক্সেস করার চেষ্টা করেন তবে d[Key_doesnt_exist][Key_doesnt_exist]এটি 0 ফিরে আসবে, এটিই সর্বশেষ ডিফল্টডিক্ট এর আর্গুমেন্টের রিটার্ন মান int()


7
এটা দুর্দান্ত কাজ! আপনি কি এই সিনট্যাক্সের পিছনে যৌক্তিক ব্যাখ্যা করতে পারেন?
জোনাথন

37
@ জোনাথন: হ্যাঁ নিশ্চিত, আপনি যখন অস্তিত্বহীন কোনও কীটি অ্যাক্সেস করার চেষ্টা করবেন তখন defaultdict(এই ক্ষেত্রে lambda : defaultdict(int)) এর যুক্তিটি কল করা হবে এবং এর ফেরতের মান এই কীটির নতুন মান হিসাবে সেট করা হবে যার অর্থ আমাদের ক্ষেত্রে এর মান d[Key_dont_exist]হবে defaultdict(int)এবং যদি আপনি এই শেষ ডিফল্টডিক্টিক্ট থেকে কোনও কী অ্যাক্সেস করার চেষ্টা করেন তবে d[Key_dont_exist][Key_dont_exist]এটি 0 ফিরে আসবে যা সর্বশেষের আর্গুমেন্টের রিটার্ন মান, defaultdictঅর্থাত্ int()আশা করি এটি সহায়ক ছিল।
12:25

25
যুক্তিটি defaultdictএকটি ফাংশন হওয়া উচিত। defaultdict(int)একটি অভিধান, যখন lambda: defaultdict(int)ফাংশনটি একটি অভিধান প্রদান করে।
has2k1

27
@ has2k1 এটি ভুল। ডিফল্টডিক্ট করার আর্গুমেন্টটি কলযোগ্য হওয়া দরকার। একটি ল্যাম্বদা একটি কলযোগ্য।
নীলস বম

2
@ রিকিলেভি, আপনি যদি এই কাজটি করতে চান তবে আপনি কেবল বলতে পারেন:defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
দারোফি

51

ডিফল্টড্রিক্ট কনস্ট্রাক্টরের প্যারামিটার হ'ল ফাংশন যা নতুন উপাদান তৈরি করার জন্য ডাকা হবে। সুতরাং একটি লাম্বদা ব্যবহার করা যাক!

>>> from collections import defaultdict
>>> d = defaultdict(lambda : defaultdict(int))
>>> print d[0]
defaultdict(<type 'int'>, {})
>>> print d[0]["x"]
0

পাইথন ২.7 থেকে, কাউন্টার ব্যবহার করে আরও একটি ভাল সমাধান রয়েছে :

>>> from collections import Counter
>>> c = Counter()
>>> c["goodbye"]+=1
>>> c["and thank you"]=42
>>> c["for the fish"]-=5
>>> c
Counter({'and thank you': 42, 'goodbye': 1, 'for the fish': -5})

কিছু বোনাস বৈশিষ্ট্য

>>> c.most_common()[:2]
[('and thank you', 42), ('goodbye', 1)]

আরও তথ্যের জন্য পাইমোটডব্লু - সংগ্রহ - পাত্রে ডেটা ধরণের এবং পাইথন ডকুমেন্টেশন - সংগ্রহ দেখুন


5
কেবলমাত্র এখানে চেনাশোনাটি সম্পূর্ণ করার জন্য, আপনি সমস্যাটিকে বিশেষভাবে উত্থাপিত হিসাবে নির্দিষ্ট করার d = defaultdict(lambda : Counter())পরিবর্তে ব্যবহার করতে চান d = defaultdict(lambda : defaultdict(int))
আড়ম্বর

3
@ গাম্পশন আপনি কেবল d = defaultdict(Counter())এই ক্ষেত্রে ল্যাম্বডার কোনও প্রয়োজন ব্যবহার করতে পারবেন না
দেব

3
@ জানুন আপনার কিছুটা ত্রুটি হয়েছে- অভ্যন্তরীণ বন্ধনীগুলি সরিয়ে ফেলুন যাতে আপনি কোনও Counterবস্তুর পরিবর্তে কলযোগ্য পাস করেন । তা হ'ল:d = defaultdict(Counter)
ডিলন ডেভিস

29

আমি এটি ব্যবহার করতে কিছুটা মার্জিত বলে মনে করি partial:

import functools
dd_int = functools.partial(defaultdict, int)
defaultdict(dd_int)

অবশ্যই এটি ল্যাম্বডা সমান।


1
আংশিক এখানে ল্যাম্বদার চেয়েও ভাল কারণ এটি পুনরাবৃত্তভাবে প্রয়োগ করা যেতে পারে :) জেনেরিক নেস্টেড ডিফল্টডিক্ট কারখানার পদ্ধতির জন্য নীচে আমার উত্তরটি দেখুন।
ক্যাম্পি

@Campi আপনি, AFAICT রিকার্সিভ অ্যাপ্লিকেশনের জন্য আংশিক প্রয়োজন হবে না
Clément

10

রেফারেন্সের জন্য, জেনেরিক নেস্টেড defaultdictকারখানার পদ্ধতিটি এর মাধ্যমে প্রয়োগ করা সম্ভব :

from collections import defaultdict
from functools import partial
from itertools import repeat


def nested_defaultdict(default_factory, depth=1):
    result = partial(defaultdict, default_factory)
    for _ in repeat(None, depth - 1):
        result = partial(defaultdict, result)
    return result()

প্রবন্ধটি সংজ্ঞায়িত প্রকারটি default_factoryব্যবহারের আগে নেস্টেড অভিধানের সংখ্যা নির্ধারণ করে । উদাহরণ স্বরূপ:

my_dict = nested_defaultdict(list, 3)
my_dict['a']['b']['c'].append('e')

আপনি একটি ব্যবহারের উদাহরণ দিতে পারেন? আমি যেভাবে এটি প্রত্যাশা করছিলাম সেভাবে কাজ করছে না। ndd = nested_defaultdict(dict) .... ndd['a']['b']['c']['d'] = 'e'নিক্ষেপKeyError: 'b'
ডেভিড মার্কস

ওহে ডেভিড, আপনাকে আপনার অভিধানের গভীরতা সংজ্ঞায়িত করতে হবে, উদাহরণস্বরূপ আপনার 3 (যেমন আপনি ডিফল্ট_ফ্যাক্টরিটিকে অভিধান হিসাবেও সংজ্ঞায়িত করেছেন ested নেস্টেড_ডিফাল্টিক্টিক্ট (ডিক্ট, 3) আপনার পক্ষে কাজ করবে
ক্যাম্পি

এটি অত্যন্ত সহায়ক ছিল, ধন্যবাদ! একটি জিনিস আমি লক্ষ্য করেছি যে এটি একটি ডিফল্ট_ডিক্ট তৈরি করে depth=0, যা কল করার সময় গভীরতা অজানা থাকলে সর্বদা পছন্দ করা যায় না। if not depth: return default_factory()ফাংশনের শীর্ষে একটি লাইন যুক্ত করে সহজেই স্থিরযোগ্য , যদিও সম্ভবত আরও মার্জিত সমাধান রয়েছে।
ব্রেন্ডন

9

পূর্ববর্তী উত্তরগুলি কীভাবে একটি দ্বি-স্তর বা এন-স্তর তৈরি করতে পারে তা সম্বোধন করেছে defaultdict। কিছু ক্ষেত্রে আপনি একটি অসীম চান:

def ddict():
    return defaultdict(ddict)

ব্যবহার:

>>> d = ddict()
>>> d[1]['a'][True] = 0.5
>>> d[1]['b'] = 3
>>> import pprint; pprint.pprint(d)
defaultdict(<function ddict at 0x7fcac68bf048>,
            {1: defaultdict(<function ddict at 0x7fcac68bf048>,
                            {'a': defaultdict(<function ddict at 0x7fcac68bf048>,
                                              {True: 0.5}),
                             'b': 3})})

1
আমি এটা ভালোবাসি. এটি শয়তানী সহজ, তবে অবিশ্বাস্যরূপে কার্যকর। ধন্যবাদ!
রসটেক্স

6

নিম্নলিখিতগুলি কীভাবে কাজ করতে হয় সে সম্পর্কে আপনার প্রশ্নের সঠিক উত্তর অন্যরা দিয়েছেন:

for x in stuff:
    d[x.a][x.b] += x.c_int

বিকল্পগুলির জন্য কীগুলির জন্য টিপলগুলি ব্যবহার করা হবে:

d = defaultdict(int)
for x in stuff:
    d[x.a,x.b] += x.c_int
    # ^^^^^^^ tuple key

এই পদ্ধতির সম্পর্কে দুর্দান্ত জিনিসটি হ'ল এটি সহজ এবং সহজেই প্রসারিত হতে পারে। আপনার যদি তিনটি স্তর গভীরভাবে ম্যাপিংয়ের প্রয়োজন হয় তবে কীটির জন্য কেবল তিনটি আইটেম টুপল ব্যবহার করুন।


4
এই সমাধানটির অর্থ হ'ল সমস্ত ডি [এক্সএ] পাওয়া সহজ নয়, কারণ টিউপলের প্রথম উপাদান হিসাবে এটির এক্সা রয়েছে কিনা তা দেখার জন্য আপনাকে প্রতিটি কীকে অন্তর্নিবেশ করতে হবে।
ম্যাথু শিনকেল

5
যদি আপনি 3 স্তর গভীর করে বাসা বাঁধতে চান, তবে কেবল এটি 3 স্তর হিসাবে সংজ্ঞা দিন: ডি = ডিফল্টডিক্ট (ল্যাম্বডা: ডিফল্টডিক্ট (ল্যাম্বদা: ডিফল্টডিক্ট (ইনট)))
ম্যাথু শিংকেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.