আমি কীভাবে একক অভিব্যক্তিতে দুটি পাইথন অভিধানকে একত্রিত করতে পারি?
অভিধানের জন্য x
এবং y
, এর z
থেকে y
প্রতিস্থাপনের মানগুলির সাথে অগভীর একত্রীকরণ করা অভিধানে পরিণত হয় x
।
পাইথন 3.5 বা তার বেশি:
z = {**x, **y}
পাইথন 2 এ (বা 3.4 বা তার চেয়ে কম) একটি ফাংশন লিখুন:
def merge_two_dicts(x, y):
z = x.copy() # start with x's keys and values
z.update(y) # modifies z with y's keys and values & returns None
return z
এবং এখন:
z = merge_two_dicts(x, y)
পাইথন 3.9.0a4 বা আরো বড় (চূড়ান্ত মুক্তির তারিখ আনুমানিক অক্টোবর 2020) ইন: PEP-584 , এখানে আলোচনা , আরও এই প্রক্রিয়া সহজ করার বাস্তবায়িত হয়েছে:
z = x | y # NOTE: 3.9+ ONLY
ব্যাখ্যা
বলুন যে আপনার দুটি ডিকট রয়েছে এবং আপনি মূল ডিক্টগুলি পরিবর্তন না করে এগুলি একটি নতুন ডিকের সাথে মার্জ করতে চান:
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
পছন্দসই ফলাফলটি হ'ল z
মানগুলির সাথে একটি নতুন অভিধান ( ) পাওয়া এবং দ্বিতীয় ডিকের মানগুলি প্রথম থেকে ওভাররাইট করে।
>>> z
{'a': 1, 'b': 3, 'c': 4}
এই জন্য একটি নতুন বাক্য গঠন, প্রস্তাব PEP 448 এবং পাইথন 3.5 এর হিসাবে উপলব্ধ হয়
z = {**x, **y}
এবং এটি প্রকৃতপক্ষে একক প্রকাশ।
মনে রাখবেন যে আমরা আক্ষরিক স্বরলিপিটির সাথেও মার্জ করতে পারি:
z = {**x, 'foo': 1, 'bar': 2, **y}
এবং এখন:
>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}
এটি এখন 3.5, পিইপি 478 এর রিলিজ শিডিয়োলে কার্যকর হিসাবে প্রদর্শিত হচ্ছে এবং এটি পাইথন 3.5 নথিতে কী নতুন রয়েছে তাতে প্রবেশ করেছে ।
তবে, যেহেতু অনেকগুলি সংস্থা এখনও পাইথন 2 এ রয়েছে, আপনি এটি পিছনের দিকে সামঞ্জস্যপূর্ণ উপায়ে করতে চাইতে পারেন। পাইথন 2 এবং পাইথন 3.0.3.4-এ উপলব্ধ ক্লাসিক্যালি পাইথোনিক উপায়টি দ্বি-পদক্ষেপ প্রক্রিয়া হিসাবে এটি করা:
z = x.copy()
z.update(y) # which returns None since it mutates z
উভয় পদ্ধতির y
মধ্যেই দ্বিতীয় আসবে এবং এর মানগুলি এর মানগুলি প্রতিস্থাপন করবে x
, এভাবে আমাদের চূড়ান্ত ফলাফলের 'b'
দিকে নির্দেশ করবে 3
।
পাইথন 3.5 তে এখনও নয়, তবে একটি একক অভিব্যক্তি চান
যদি আপনি এখনও পাইথন 3.5 তে নেই, বা পশ্চাতে-সামঞ্জস্যপূর্ণ কোড লেখার দরকার পড়ে এবং আপনি এটি একটি একক অভিব্যক্তিতে চান , সঠিক পদ্ধতির সময় এটি একটি ফাংশনটিতে রাখার জন্য সবচেয়ে পারফরম্যান্স:
def merge_two_dicts(x, y):
"""Given two dicts, merge them into a new dict as a shallow copy."""
z = x.copy()
z.update(y)
return z
এবং তারপরে আপনার একক প্রকাশ হবে:
z = merge_two_dicts(x, y)
আপনি শূন্য থেকে খুব বড় সংখ্যায় একটি নির্ধারিত সংখ্যক ডিক্টগুলিকে মার্জ করার জন্য একটি ফাংশনও তৈরি করতে পারেন:
def merge_dicts(*dict_args):
"""
Given any number of dicts, shallow copy and merge into a new dict,
precedence goes to key value pairs in latter dicts.
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
এই ফাংশনটি সমস্ত ডিক্টের জন্য পাইথন 2 এবং 3 এ কাজ করবে। প্রদত্ত dicts যেমন a
করতে g
:
z = merge_dicts(a, b, c, d, e, f, g)
এবং কী মান জোড়া g
dicts বেশি প্রাধান্য নিতে হবে a
থেকে f
, ইত্যাদি।
অন্যান্য উত্তরের সমালোচনা
আপনি পূর্বে গৃহীত উত্তরে যা দেখেন তা ব্যবহার করবেন না:
z = dict(x.items() + y.items())
পাইথন 2 এ, আপনি প্রতিটি ডিকের জন্য মেমরিতে দুটি তালিকাগুলি তৈরি করেন, মেমোরিতে তৃতীয় তালিকার প্রথম দুটি দৈর্ঘ্যের সমান দৈর্ঘ্যের সাথে একত্রে তৈরি করুন এবং তারপরে ডিকটি তৈরি করতে সমস্ত তিনটি তালিকা বাতিল করুন। পাইথন 3 এ এটি ব্যর্থ হবে কারণ আপনি দুটি dict_items
তালিকাকে নয় দুটি পদ যুক্ত করে রেখেছেন -
>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'
এবং আপনি তাদের স্পষ্টভাবে তালিকা হিসাবে তৈরি করতে হবে, যেমন z = dict(list(x.items()) + list(y.items()))
। এটি সম্পদ এবং গণনার শক্তি অপচয়।
একইভাবে, items()
পাইথন 3-তে ( viewitems()
পাইথন ২.7-এ) ইউনিয়ন নেওয়াও ব্যর্থ হবে যখন মানগুলি অনিবার্য বস্তু হয় (উদাহরণস্বরূপ, তালিকাগুলি)। এমনকি যদি আপনার মানগুলি হ্যাশযোগ্য হয় তবে সেটগুলি শব্দার্থবিজ্ঞানহীন, তাই আচরণটি অগ্রাধিকারের সাথে সম্পর্কিত নয়। সুতরাং এটি করবেন না:
>>> c = dict(a.items() | b.items())
এই উদাহরণটি প্রদর্শিত হয় যখন মানগুলি অদৃশ্যযোগ্য হয় তখন কী ঘটে:
>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
এখানে একটি উদাহরণ রয়েছে যেখানে y এর অগ্রাধিকার থাকা উচিত তবে পরিবর্তে x এর মানটি সেটগুলির স্বেচ্ছাসেবী আদেশের কারণে ধরে রাখা যায়:
>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}
অন্য হ্যাক আপনি ব্যবহার করা উচিত নয়:
z = dict(x, **y)
এটি dict
কনস্ট্রাক্টরটি ব্যবহার করে , এবং খুব দ্রুত এবং স্মৃতিশক্তি দক্ষ (আমাদের দ্বি-পদক্ষেপের প্রক্রিয়াটির তুলনায় কিছুটা আরও বেশি) তবে আপনি যদি এখানে সুনির্দিষ্টভাবে জানেন না তবে (যা, দ্বিতীয় ডিকটি ডিকের কীওয়ার্ড আর্গুমেন্ট হিসাবে পাস হচ্ছে কনস্ট্রাক্টর), এটি পড়া শক্ত, এটি উদ্দেশ্যযুক্ত ব্যবহার নয় এবং তাই এটি পাইথোনিক নয়।
জাঙ্গোতে প্রতিকারের ব্যবহারের উদাহরণ এখানে দেওয়া হয়েছে ।
ডিকটগুলি হ্যাশেবল কীগুলি (যেমন হিমায়িত বা টিপলস) নেওয়ার উদ্দেশ্যে করা হয়, তবে কীগুলি স্ট্রিং না থাকায় পাইথন 3 এ এই পদ্ধতিটি ব্যর্থ হয়।
>>> c = dict(a, **b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
থেকে মেইলিং লিস্ট , গাইডো van Rossum, ভাষা স্রষ্টার, লিখেছেন:
ডিক ({}, ** {1: 3}) অবৈধ ঘোষণা করার সাথে আমি ঠিক আছি, কারণ এটি সর্বোপরি ** প্রক্রিয়াটির অপব্যবহার।
এবং
স্পষ্টতই ডিক (x, ** y) "কুল x.update (y) এবং রিটার্ন এক্স" এর জন্য "কুল হ্যাক" হিসাবে ঘুরছে। ব্যক্তিগতভাবে আমি এটিকে শীতল চেয়েও তুচ্ছ মনে করি find
এটি আমার বোঝাপড়া (পাশাপাশি ভাষাটির স্রষ্টার বোঝা ) dict(**y)
যেটির জন্য ব্যবহারিক ব্যবহারটি পাঠযোগ্যতার উদ্দেশ্যে ডিক্টস তৈরি করার জন্য, যেমন:
dict(a=1, b=10, c=11)
পরিবর্তে
{'a': 1, 'b': 10, 'c': 11}
মন্তব্য প্রতিক্রিয়া
গুইডো যা বলেন তা সত্ত্বেও dict(x, **y)
ডিক স্পেসিফিকেশনের সাথে সামঞ্জস্য রয়েছে, যা বিটিডব্লিউ। পাইথন 2 এবং 3 উভয়ের জন্যই কাজ করে যা সত্য যে স্ট্রিং কীগুলির জন্য এটি কেবল কাজ করে কীওয়ার্ড পরামিতিগুলি কীভাবে ডিকের সংক্ষিপ্ত আগমন নয় এটির সরাসরি ফলাফল। বা এই জায়গায় ** অপারেটরটি এই ব্যবস্থার অপব্যবহারের ব্যবহার করছে না, আসলে ** কীওয়ার্ড হিসাবে ডিক্টগুলি পাস করার জন্য সঠিকভাবে তৈরি করা হয়েছিল।
আবার, 3 টির জন্য কাজ হয় না যখন কীগুলি অ-স্ট্রিং থাকে। অন্তর্নিহিত কলিং চুক্তি হ'ল নেমস্পেসগুলি সাধারণ ডিকট নেয়, যখন ব্যবহারকারীদের কেবল স্ট্রিংগুলির মূল শব্দটি যুক্ত করতে হবে pass অন্যান্য সমস্ত কলযোগ্যরা এটি প্রয়োগ করে। dict
পাইথন 2 এ এই ধারাবাহিকতাটি ভেঙেছে:
>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}
পাইথনের অন্যান্য প্রয়োগগুলি (পাইপি, জাইথন, আয়রন পাইথন) দেওয়া হলেও এই অসঙ্গতি খারাপ ছিল। সুতরাং এটি পাইথন 3 এ স্থির করা হয়েছিল, কারণ এই ব্যবহারটি একটি ব্রেকিং পরিবর্তন হতে পারে।
আমি আপনাকে জমা দিয়েছি যে ইচ্ছাকৃতভাবে কোড লিখতে দূষিত অক্ষমতা যা কেবল কোনও ভাষার একটি সংস্করণে কাজ করে বা নির্দিষ্ট কিছু স্বেচ্ছাসেবী সীমাবদ্ধতার ভিত্তিতে কেবল কাজ করে।
আরও মন্তব্য:
dict(x.items() + y.items())
পাইথন 2 এর জন্য এখনও সর্বাধিক পঠনযোগ্য সমাধান Read পাঠযোগ্যতার গণনা।
আমার প্রতিক্রিয়া: merge_two_dicts(x, y)
আসলে আমাদের কাছে আরও স্পষ্ট মনে হয়, যদি আমরা পড়ার যোগ্যতার বিষয়ে আসলেই উদ্বিগ্ন। পাইথন 2 ক্রমশ অবচিত হওয়ায় এটি সামঞ্জস্যপূর্ণ নয়।
{**x, **y}
নেস্টেড অভিধানগুলি হ্যান্ডেল করে না বলে মনে হচ্ছে। নেস্টেড কীগুলির বিষয়বস্তুগুলি কেবল ওভাররাইট করা হয়, একত্রিত হয় না [...] আমি এই উত্তরগুলি দ্বারা বার বার পোড়াও শেষ হয়ে গেলাম যা পুনরাবৃত্তভাবে মার্জ হয় না এবং আমি অবাক হয়ে গিয়েছিলাম যে এটির কোনও উল্লেখ নেই। আমার "মার্জিং" শব্দের ব্যাখ্যায় এই উত্তরগুলি "একটি ডিকের সাথে অন্যের সাথে আপডেট করা" এবং মার্জ না করে বর্ণনা করে।
হ্যাঁ. আমি আপনাকে অবশ্যই সেই প্রশ্নের দিকে ফিরে যেতে হবে, যা দুটি অভিধানের অগভীর একত্রীকরণের জন্য জিজ্ঞাসা করছে , প্রথমটির মানগুলি দ্বিতীয়টির দ্বারা মুছে ফেলা হয় - একক অভিব্যক্তিতে।
অভিধানের দুটি অভিধান অনুমান করে, কেউ এগুলি একক ফাংশনে পুনরাবৃত্তভাবে মার্জ করতে পারে তবে আপনার কোনও উত্স থেকে ডিক্টগুলি সংশোধন না করার বিষয়ে সতর্কতা অবলম্বন করা উচিত এবং মানগুলি নির্ধারণের সময় অনুলিপিটি এড়ানোর নিশ্চিত উপায়। যেহেতু কীগুলি হ্যাশযোগ্য এবং সাধারণত অপরিবর্তনীয় তাই এগুলি অনুলিপি করা অর্থহীন:
from copy import deepcopy
def dict_of_dicts_merge(x, y):
z = {}
overlapping_keys = x.keys() & y.keys()
for key in overlapping_keys:
z[key] = dict_of_dicts_merge(x[key], y[key])
for key in x.keys() - overlapping_keys:
z[key] = deepcopy(x[key])
for key in y.keys() - overlapping_keys:
z[key] = deepcopy(y[key])
return z
ব্যবহার:
>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}
অন্যান্য মান ধরণের জন্য জরুরী অবস্থা নিয়ে আসা এই প্রশ্নের পরিধি থেকে অনেক দূরে, সুতরাং আমি আপনাকে "অভিধানের সংশ্লেষের সংশ্লেষের ডিকোরিশনস" এর নীতিগত প্রশ্নের উত্তরটি আপনার দিকে তুলে ধরব ।
কম পারফরম্যান্ট তবে সঠিক অ্যাড-হকস
এই পদ্ধতিগুলি কম পারফরম্যান্ট তবে তারা সঠিক আচরণ সরবরাহ করবে। তারা থাকবে অনেক কম চেয়ে performant copy
এবং update
বা নতুন আন-প্যাক কারণ তারা বিমূর্ততা একটি উচ্চ পর্যায়ে প্রত্যেক কী-মান জোড়া মাধ্যমে পুনরুক্তি, কিন্তু তারা কি (আধুনিক dicts প্রাধান্য আছে) পূর্ববর্তিতার ক্রম সম্মান
আপনি ডিক বোঝার ভিতরে ডিক্টসকে ম্যানুয়ালি চেইন করতে পারেন:
{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7
বা পাইথন ২.6 এ (এবং সম্ভবত জেনারেটর এক্সপ্রেশন চালু হওয়ার সময় 2.4 এর প্রথম দিকে):
dict((k, v) for d in dicts for k, v in d.items())
itertools.chain
সঠিক ক্রমে পুনরাবৃত্তিকে মূল-মান জোড়ের উপর শৃঙ্খলাবদ্ধ করবে:
import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))
কর্মক্ষমতা বিশ্লেষণ
আমি কেবল ব্যবহার করতে পারি সঠিকভাবে আচরণ করার জন্য ব্যবহারের বিশ্লেষণ বিশ্লেষণ করতে।
import timeit
নিম্নলিখিত উবুন্টু 14.04 এ করা হয়
পাইথন ২.7 (সিস্টেম পাইথন) এ:
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934
পাইথন 3.5 তে (মৃতদেহ পিপিএ):
>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287
অভিধানে সংস্থান
z = x | y