পাইথনে আমি কীভাবে দুটি শব্দকোষ একক অভিব্যক্তিতে মার্জ করব?


4778

আমার দুটি পাইথন অভিধান রয়েছে এবং আমি একটি একক অভিব্যক্তি লিখতে চাই যা এই দুটি অভিধানকে একত্রিত করে ফেরত দেয়। update()পদ্ধতি হবে আমি কি প্রয়োজন, যদি তার ফলাফলের ফিরে পরিবর্তে ইন-জায়গা একটি অভিধান পরিবর্তন।

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

আমি কীভাবে সেই চূড়ান্ত মার্জড ডিকশনারিটি পেতে পারি z, না x?

(অতিরিক্ত স্পষ্ট করে বলতে গেলে, সর্বশেষ একের মধ্যে লড়াইয়ের বিরোধ-হ্যান্ডলিং dict.update()হ'ল আমিও যা খুঁজছি))


আপনি পাইথন ৩.৯ আলফা ব্যবহার করছেন এমন অফ সুযোগে, কেবল ব্যবহার করুনz = x | y
দ্য ডেলিকস

উত্তর:


5679

আমি কীভাবে একক অভিব্যক্তিতে দুটি পাইথন অভিধানকে একত্রিত করতে পারি?

অভিধানের জন্য 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) 

এবং কী মান জোড়া gdicts বেশি প্রাধান্য নিতে হবে 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

অভিধানে সংস্থান


9
@ মোহাম্মদআজিম "স্ট্রিং কেবলমাত্র" কেবলমাত্র কলরেবলগুলিতে মূলশব্দ যুক্তি প্রসারণের ক্ষেত্রে প্রযোজ্য, আনপ্যাকিং সিনট্যাক্সকে সাধারণীকরণ করা হয়নি। এটি কাজ করে তা দেখানোর জন্য: {**{(0, 1):2}}->{(0, 1): 2}
অ্যারন হল

36
সংক্ষিপ্ত উত্তরগুলি z = {**x, **y}সত্যই আমাকে উদ্দীপিত করে
pcko1

3
আমি "দূষিত অক্ষমতা" অংশের জন্য উন্নীত করেছি।
ডন হ্যাচ

2
যখন উত্তরের শীর্ষে একটি সংক্ষিপ্তসার প্রয়োজন তখন এটি খুব দীর্ঘ।
গ্রিঙ্গো সুভেভ 17

2
হাই, শীর্ষটি হ'ল একটি সংক্ষিপ্তসার। আপনার উপর পুরো জিনিসটি একটি দুর্দান্ত ব্লগ পোস্ট হবে। দ্রষ্টব্য পিআই 3.4 এবং নীচে রয়েছে ইওএল, 3.5 টি 2020-09-এ EOL এ আসছে।
গ্রিংগো সুভেভ

1615

আপনার ক্ষেত্রে, আপনি যা করতে পারেন তা হ'ল:

z = dict(x.items() + y.items())

এটি, যেমনটি আপনি এটি চান, চূড়ান্ত ডিকটি এতে প্রবেশ করবে এবং zকীটির মানটি bদ্বিতীয় ( y) ডিকের মান দ্বারা যথাযথভাবে ওভাররাইড করা হবে :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

যদি আপনি পাইথন 3 ব্যবহার করেন তবে এটি কেবল আরও জটিল। তৈরি করতে z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

আপনি যদি পাইথন সংস্করণ 3.9.0a4 বা তার বেশি ব্যবহার করেন তবে আপনি সরাসরি ব্যবহার করতে পারেন:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = x | y
print(z)

Output: {'a': 1, 'c': 11, 'b': 10}

1
এটি খুব অদক্ষ তাই এটি ব্যবহার করবেন না। (নীচের সময়সীমার ফলাফলগুলি দেখুন)) পাইপ 2 দিনগুলিতে এটি আবশ্যক ছিল যদি একটি মোড়কের ফাংশন কোনও বিকল্প না ছিল তবে সেই দিনগুলি এখন অতীত।
গ্রিংগো সুভেভ

632

একটি বিকল্প:

z = x.copy()
z.update(y)

83
এটি কেন প্রশ্নটির দ্বারা প্রদত্ত ক্রাইটের সাথে মেলে না তা পরিষ্কার করতে: এটি কোনও একক অভিব্যক্তি নয় এবং এটি জেড ফিরে আসে না।
অ্যালেক্স

2
@ নিউরনেট প্রতিটি অনেলাইনার সাধারণত কেবল চলন্ত কোড যা একটি ভিন্ন উপাদান মধ্যে ঘটতে হবে এবং এটি সেখানে সমাধান করে। এটি অবশ্যই একটি ক্ষেত্রে। তবে অন্যান্য ভাষার কাছে এটির জন্য পাইথনের চেয়েও ভাল নির্মাণ রয়েছে। এবং একটি উল্লেখযোগ্য স্বচ্ছ বৈকল্পিক থাকা যা এটির উপাদান দেয় এটি জিনিসটি পেয়ে খুব ভাল।
অ্যালেক্স

12
এটি এইভাবে রাখুন: আপনি যদি আপনার কোডটি লোকেদের হাতে তুলে দেন এমন লোকদের কাছে আপনার এক কোডের কোডের ব্যাখ্যা দেওয়ার জন্য মন্তব্যগুলির দুটি লাইনের প্রয়োজন আছে ... আপনি কি সত্যিই এটি একটি লাইনে করেছেন? :) আমি পুরোপুরি সম্মত হই যে পাইথন এর পক্ষে ভাল নয়: আরও সহজ উপায় থাকা উচিত। যদিও এই উত্তরটি আরও অজগর, তবে এটি কি এতটা স্পষ্ট বা পরিষ্কার? Updateলোকেরা প্রচুর ব্যবহার করার প্রবণতাগুলির মধ্যে একটি "মূল" ফাংশন নয়।
এরিক

ঠিক আছে, লোকেরা যদি এটি অনেলাইনার হিসাবে গড়ে তোলার জন্য জোর দেয় তবে আপনি সর্বদা এটি করতে পারেন (lambda z: z.update(y) or z)(x.copy()): পি
টাওয়ার

339

আরেকটি, আরও সংক্ষিপ্ত, বিকল্প:

z = dict(x, **y)

দ্রষ্টব্য : এটি একটি জনপ্রিয় উত্তর হয়ে উঠেছে, তবে এটি উল্লেখ করা গুরুত্বপূর্ণ যে যদি yকোনও স্ট্রিং কী থাকে তবে এটি যে সত্যিকার অর্থে কাজ করে তা সিপিথন বাস্তবায়ন বিশদর অপব্যবহার এবং এটি পাইথন 3 তে কাজ করে না, বা পাইপাই, আয়রন পাইথন বা জাইথনে। এছাড়াও, গুইডো কোনও ভক্ত নয় । সুতরাং আমি ফরওয়ার্ড-সামঞ্জস্যপূর্ণ বা ক্রস-বাস্তবায়ন পোর্টেবল কোডের জন্য এই কৌশলটি সুপারিশ করতে পারি না, যার সত্যিকার অর্থে এটি পুরোপুরি এড়ানো উচিত।


পাইথন 3 এবং পাইপাই এবং পাইপাই 3 এ দুর্দান্ত কাজ করে , জাইথন ​​বা আয়রনের সাথে কথা বলতে পারে না। প্রদত্ত এই প্যাটার্নটি স্পষ্টভাবে নথিভুক্ত করা হয়েছে (এই ডকুমেন্টেশনে তৃতীয় কনস্ট্রাক্টর ফর্মটি দেখুন) আমি যুক্তি দেব যে এটি কোনও "বাস্তবায়ন বিশদ" নয় তবে ইচ্ছাকৃত বৈশিষ্ট্য ব্যবহার নয়।
amcgregor

5
@amcgregor আপনি "যদি y এর কোনও নন-স্ট্রিং কী থাকে" তবে আপনি মূল বাক্যাংশটি মিস করেছেন। পাইথন 3 এ যা কাজ করে না; এটি সিপিথন 2 এ কাজ করে এমন বাস্তবায়ন বিশদ যা নির্ভর করা যায় না। যদি আপনার সমস্ত কীগুলি স্ট্রিং হওয়ার গ্যারান্টিযুক্ত হয় তবে এটি সম্পূর্ণ সমর্থনযোগ্য বিকল্প।
কার্ল মায়ার

213

এটি সম্ভবত একটি জনপ্রিয় উত্তর হবে না, তবে আপনি প্রায় অবশ্যই এটি করতে চান না। আপনি যদি একত্রিত হওয়া একটি অনুলিপি চান, তবে অনুলিপি (বা ডিপকপি , আপনি যা চান তার উপর নির্ভর করে) ব্যবহার করুন এবং তারপরে আপডেট করুন। কোডের দুটি লাইন অনেক বেশি পঠনযোগ্য - পাইথোনিক - .items () + .items () সহ একক লাইন তৈরির চেয়ে বেশি Py সুস্পষ্ট বর্ণিত চেয়ে ভাল।

এছাড়াও, আপনি যখন .items () (পাইথন 3.0 এর পূর্ব) ব্যবহার করেন, আপনি ডিকের আইটেমগুলিতে একটি নতুন তালিকা তৈরি করবেন। যদি আপনার অভিধানগুলি বড় হয়, তবে এটি যথেষ্ট পরিমাণে ওভারহেড (দুটি বড় তালিকা যা মার্জড ডিকটি তৈরি হওয়ার সাথে সাথে ফেলে দেওয়া হবে) away আপডেট () আরও দক্ষতার সাথে কাজ করতে পারে, কারণ এটি দ্বিতীয় ডিক্ট আইটেম বাই আইটেমের মাধ্যমে চলতে পারে।

সময়ের নিরিখে :

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

আইএমও প্রথম দু'জনের মধ্যে ক্ষুদ্র মন্দা পড়ার পক্ষে উপযুক্ত। এছাড়াও, অভিধান তৈরির জন্য কীওয়ার্ড আর্গুমেন্টগুলি পাইথন ২.৩ এ কেবল যুক্ত করা হয়েছিল, যেখানে অনুলিপি () এবং আপডেট () পুরানো সংস্করণগুলিতে কাজ করবে।


149

অনুসরণীয় উত্তরে, আপনি এই দুটি বিকল্পের আপেক্ষিক কার্য সম্পাদন সম্পর্কে জিজ্ঞাসা করেছেন:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

আমার মেশিনে, কমপক্ষে (পাইথন 2.5.2 চালিত মোটামুটি সাধারণ x86_64) বিকল্পটি z2কেবল খাটো এবং সরলই নয় তবে তাড়াতাড়ি দ্রুতগতিতেও আসে। timeitপাইথনের সাথে আসা মডিউলটি ব্যবহার করে আপনি এটি নিজের জন্য যাচাই করতে পারেন ।

উদাহরণ 1: অভিন্ন অভিধানগুলি নিজেরাই 20 টি টানা পূর্ণসংখ্যার ম্যাপিং করছে:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z23.5 বা এর একটি ফ্যাক্টর দ্বারা জিতেছে। বিভিন্ন অভিধানে বেশ আলাদা ফলাফল পাওয়া যায় z2বলে মনে হয় তবে সবসময় সামনে এসে উপস্থিত বলে মনে হয়। (যদি আপনি একই পরীক্ষার জন্য বেমানান ফলাফল পান -rতবে ডিফল্ট ৩ এর চেয়ে বড় সংখ্যার সাথে পাস করার চেষ্টা করুন ))

উদাহরণ 2: অ-ওভারল্যাপিং অভিধানগুলি 252 সংক্ষিপ্ত স্ট্রিংগুলিকে পূর্ণসংখ্যার সাথে ম্যাপিং করে এবং বিপরীতে:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 প্রায় দশমিক দশমিক এক ফ্যাক্টর দ্বারা জিতেছে এটি আমার বইয়ের বেশ বড় জয়!

এই দু'টির তুলনা করার পরে, আমি ভাবলাম z1যে দু'টি আইটেমের তালিকা তৈরির ওভারহেডের দুর্বল পারফরম্যান্সকে দায়ী করা যেতে পারে, যার ফলশ্রুতিতে আমাকে ভাবতে হয়েছিল যে এই প্রকরণটি আরও ভালভাবে কাজ করতে পারে:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

কয়েকটি দ্রুত পরীক্ষা, যেমন

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

আমাকে এই উপসংহারে নিয়ে যেতে হবে যে এর z3চেয়ে কিছুটা দ্রুত z1, তবে ততটা দ্রুত নয় z2। সমস্ত অতিরিক্ত টাইপিংয়ের অবশ্যই মূল্য নেই।

এই আলোচনাটি এখনও গুরুত্বপূর্ণ কিছু অনুপস্থিত, যা দুটি তালিকার মার্জ করার "সুস্পষ্ট" পদ্ধতির সাথে এই বিকল্পগুলির একটি পারফরম্যান্স তুলনা: updateপদ্ধতিটি ব্যবহার করে । এক্সপ্রেশনের সাথে জিনিসগুলিকে সমান পদক্ষেপে রাখার চেষ্টা করার জন্য, যার মধ্যে x বা y কে কোনও পরিবর্তন করে না, আমি x এর অনুলিপি পরিবর্তে স্থানের পরিবর্তে একটি অনুলিপি তৈরি করতে যাচ্ছি:

z0 = dict(x)
z0.update(y)

একটি সাধারণ ফলাফল:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

অন্য কথায়, z0এবং z2মনে হয় মূলত অভিন্ন কর্মক্ষমতা রয়েছে। আপনি কি মনে করেন এটি একটি কাকতালীয় ঘটনা হতে পারে? আমি না ....

প্রকৃতপক্ষে, আমি এতদূর যেতে পেরেছি যে খাঁটি পাইথন কোডের পক্ষে এর চেয়ে আরও ভাল কিছু করা অসম্ভব। এবং যদি আপনি কোনও সি এক্সটেনশান মডিউলে উল্লেখযোগ্যভাবে আরও ভাল করতে পারেন তবে আমি কল্পনা করি পাইথন ভাবেন আপনার কোডটি (বা আপনার পদ্ধতির কোনও প্রকরণ) পাইথন কোরটিতে অন্তর্ভুক্ত করতে আগ্রহী হতে পারেন। পাইথন dictপ্রচুর জায়গায় ব্যবহার করে ; এর অপারেশনগুলি অনুকূল করা একটি বড় ব্যাপার।

আপনি এটি হিসাবে লিখতে পারে

z0 = x.copy()
z0.update(y)

টনি যেমন করেন, তবে (আশ্চর্যরূপে নয়) স্বরলিখনের পার্থক্যের কারণে পারফরম্যান্সে কোনও পরিমাপযোগ্য প্রভাব না পড়ে। আপনার যেদিকে ডান লাগছে তা ব্যবহার করুন। অবশ্যই, তিনি এ কথাটি বলতে একেবারেই সঠিক যে দ্বি-বিবৃতি সংস্করণটি বোঝা অনেক সহজ।


5
পাইথন 3 এ এটি কাজ করে না; items()খাওয়ার যোগ্য নয় এবং এর iteritemsঅস্তিত্ব নেই।
আন্তি হাপাল

126

পাইথনcollections.ChainMap 3.0.০ এবং তারপরে, আপনি একক, আপডেটযোগ্য দৃশ্য তৈরি করতে কোন দলকে একাধিক ডিক্টস বা অন্যান্য ম্যাপিং একসাথে ব্যবহার করতে পারেন :

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(ChainMap({}, y, x))
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11

পাইথন 3.5 এবং তার পরে আপডেট : আপনি পিইপি 448 বর্ধিত অভিধান প্যাকিং এবং আনপ্যাকিং ব্যবহার করতে পারেন use এটি দ্রুত এবং সহজ:

>>> x = {'a':1, 'b': 2}
>>> y = y = {'b':10, 'c': 11}
>>> {**x, **y}
{'a': 1, 'b': 10, 'c': 11}

3
চ্যানম্যাপটি ব্যবহার করার সময় একটি সতর্ক হওয়া উচিত যে আপনার কাছে যদি ডুপ্লিকেট কী থাকে তবে প্রথম ম্যাপিংয়ের মানগুলি ব্যবহার হয়ে যায় এবং যখন আপনি কোনও কল delকরেন একটি চেইনম্যাপ সি সেই কীটির প্রথম ম্যাপিংটি মুছে ফেলবে।
স্লেয়ার

7
@ প্ররিত আপনি আর এটি কী করবেন বলে আশা করবেন? শৃঙ্খলিত নেমস্পেসগুলি এটাই সাধারণ উপায়। PATH কীভাবে ব্যাশে কাজ করে তা বিবেচনা করুন। পথে এক্সিকিউটেবলকে মুছে ফেলা একই নামে আরও কার্যকর করা যায় না এবং আরও প্রবাহিত হয়।
রেমন্ড হেটেঙ্গার

2
@ রেমন্ড হেট্টিংগার আমি একমত, মাত্র একটি সতর্কতা যুক্ত করেছি। বেশিরভাগ মানুষ এটি সম্পর্কে জানেন না। : ডি
স্লেয়ার

@ প্ররিট আপনি dictএড়াতে কাস্ট করতে পারেন, যেমন:dict(ChainMap({}, y, x))
ওয়াজান্দ্রিয়া

112

আমি অনুরূপ কিছু চেয়েছিলাম, তবে সদৃশ কীগুলির মানগুলি কীভাবে একীভূত হয়েছিল তা নির্দিষ্ট করার ক্ষমতা দিয়ে, তাই আমি এটিকে হ্যাক করেছি (তবে এটি খুব বেশি পরীক্ষা করে দেখিনি)। স্পষ্টতই এটি কোনও একক অভিব্যক্তি নয়, তবে এটি একটি একক ফাংশন কল।

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

87

Recursively / গভীর আপডেট একটি ডিক

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

প্রদর্শন:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

আউটপুট:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

সম্পাদনার জন্য ধন্যবাদ rednaw।


1
এটি প্রশ্নের উত্তর দেয় না। প্রশ্নটি স্পষ্টভাবে একটি নতুন অভিধানের জন্য জিজ্ঞাসা করবে, z, মূল অভিধান থেকে x এবং y, y এর সাথে x এর পরিবর্তে মানগুলি - কোনও আপডেট হওয়া অভিধান নয়। এই উত্তরটি x থেকে মান যোগ করে y-in-place পরিবর্তন করে। সবচেয়ে খারাপ বিষয়, এটি এই মানগুলি অনুলিপি করে না, সুতরাং কেউ আরও পরিবর্তিত অভিধান, y এবং সংশোধন করতে পারে এবং অভিধানে এক্সটি সংশোধন করতে পারে। @ জেরোমে আমি আশা করি এই কোডটি আপনার আবেদনের জন্য কোনও বাগ তৈরি করছে না - কমপক্ষে মানগুলি অনুলিপি করতে ডিপকপি ব্যবহারের বিষয়ে বিবেচনা করুন।
হারুন হলের

1
@ অ্যারনহল সম্মত হয়েছে এটি প্রশ্নের উত্তর দেয় না। তবে এটি আমার প্রয়োজনের জবাব দেয়। আমি এই সীমাবদ্ধতাগুলি বুঝতে পারি, তবে এটি আমার ক্ষেত্রে কোনও সমস্যা নয়। এটি ভেবে, সম্ভবত নামটি বিভ্রান্ত করছে, কারণ এটি কোনও ডিপকপি তৈরি করতে পারে যা এটি সরবরাহ করে না। তবে এটি গভীর বাসা বাঁধে। এখানে মার্টেলিবোট থেকে আরও একটি বাস্তবায়ন: স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / ৩৩২২৯৩৩/২
জেরুমে

71

অনুলিপি ব্যবহার না করার সময় আমি ভাবতে পারি সেরা সংস্করণটি হ'ল:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

এটি কমপক্ষে সিপিথনের চেয়ে দ্রুত dict(x.items() + y.items())তবে তত দ্রুত নয় n = copy(a); n.update(b)। যদি আপনি পরিবর্তন এই সংস্করণ এছাড়াও পাইথন 3 কাজ iteritems()করতে items(), যা স্বয়ংক্রিয়ভাবে 2to3 টুল দ্বারা সম্পন্ন করা হয়।

ব্যক্তিগতভাবে আমি এই সংস্করণটি সবচেয়ে পছন্দ করি কারণ এটি একটি একক কার্যকরী বাক্য গঠনতে আমি যা চাই তা মোটামুটি ভাল বর্ণনা করে। একমাত্র ছোটখাটো সমস্যা হ'ল এটি সম্পূর্ণ সুস্পষ্ট করে তোলে না যে y এর মানগুলি x থেকে প্রাপ্ত মানগুলির চেয়ে অগ্রাধিকার নেয়, তবে আমি বিশ্বাস করি না যে এটি নির্ধারণ করা শক্ত difficult


70

পাইথন 3.5 (পিইপি 448) একটি সুন্দর সিনট্যাক্স বিকল্পের অনুমতি দেয়:

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

অথবা এমনকি

final = {'a': 1, 'b': 1, **x, **y}

পাইথন ৩.৯-এ আপনিও ব্যবহার করেন এবং | = পিইপি 584 থেকে নীচের উদাহরণ সহ

d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

এই সমাধানটি সমাধান-সমাধানের চেয়ে কীভাবে ভাল dict(x, **y)? আপনি (@CarlMeyer) আপনার নিজের উত্তর (এর নোট মধ্যে উল্লেখ করা হয়েছে stackoverflow.com/a/39858/2798610 ) গাইডো যে সমাধান বিবেচনা করে অবৈধ
ব্লেকাগল ৫২

14
গিডো dict(x, **y)(খুব ভাল) কারণে অপছন্দ করে যে এটি yকেবল কীগুলির উপর নির্ভর করে যা বৈধ কীওয়ার্ড আর্গুমেন্টের নাম (যদি আপনি সিপিথন ২.7 ব্যবহার করেন না, যেখানে ডিক্ট কনস্ট্রাক্টর চিট করে)। এই আপত্তি / সীমাবদ্ধতা পিইপি 448 এর জন্য প্রযোজ্য নয়, যা **ডিক আক্ষরিকগুলিতে আনপ্যাকিং সিনট্যাক্সকে সাধারণীকরণ করে । সুতরাং এই সমাধানটির সমান সংক্ষিপ্তসার রয়েছে dict(x, **y), ডাউনসাইড ছাড়া।
কার্ল মায়ার

61
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

উভয় অভিধানে কী যুক্ত আইটেমগুলির জন্য ('বি'), আপনি এটি নিয়ন্ত্রণ করতে পারেন কোনটি শেষের দ্বারা আউটপুটে শেষ হয়।


পাইথন 3-তে আপনি টাইপ-এরর পাবেন: অসমর্থিত অপারেন্ড টাইপ (গুলি) এর জন্য +: 'ডিক_াইটেমস' এবং 'ডিকাইটাইটস' ... আপনার প্রতিটি ডিককে তালিকার সাথে আবদ্ধ করা উচিত (যেমন: ডিক (তালিকা (x.items ()) + তালিকা (y.items ()))
জাস্টসেইড

49

যদিও ইতিমধ্যে বেশ কয়েকবার প্রশ্নের উত্তর দেওয়া হয়েছে, তবে সমস্যার এই সহজ সমাধানটি এখনও তালিকাভুক্ত করা হয়নি।

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

এটি Z0 এবং উপরে উল্লিখিত অশুভ z2 এর মতো দ্রুত, তবে বুঝতে এবং পরিবর্তন করা সহজ।


3
কিন্তু এটা এক অভিব্যক্তি বদলে তিন বিবৃতি এর
ফোরট্রান

14
হ্যাঁ! উল্লিখিত ওয়ান-এক্সপ্রেশন-সমাধানগুলি হয় ধীর বা খারাপ or ভাল কোড পাঠযোগ্য এবং রক্ষণাবেক্ষণযোগ্য। সুতরাং সমস্যাটি প্রশ্নের উত্তর নয়। আমাদের সমস্যার সমাধান করার জন্য এক-লাইন সমাধানের জন্য নয়।
ফোবি

7
হারাতে z4 = {}এবং পরবর্তী লাইনটি পরিবর্তন করুন z4 = x.copy()- ভাল কোডের চেয়ে ভাল ভাল অপ্রয়োজনীয় জিনিস না করে (এটি এটিকে আরও পাঠযোগ্য এবং রক্ষণাবেক্ষণযোগ্য করে তোলে)।
মার্টিনো

3
আপনার পরামর্শটি ম্যাথিউজের উত্তরে এটিকে পরিবর্তন করবে। যদিও তার উত্তরটি ঠিক আছে, আমার ধারণা আমার পাঠযোগ্য এবং আরও ভাল রক্ষণাবেক্ষণযোগ্য। অতিরিক্ত লাইনটি কেবল তখনই খারাপ হয় যদি এটির প্রয়োগের সময় ব্যয় হয়।
ফোবি

47
def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

এই ধরনের ছায়াময় এবং সন্দেহজনক উত্তরের মধ্যে, এই উজ্জ্বল উদাহরণটি পাইথনে ডিক্টসকে একীভূত করার একমাত্র এবং ভাল উপায়, যা জীবনের জন্য স্বৈরশাসকের পক্ষ থেকে গৃহীত হয়েছে গুডো ভ্যান রসুম নিজেই! অন্য কেউ এর অর্ধেক পরামর্শ দিয়েছিল, তবে এটি কোনও কার্যক্রমে রাখেনি।

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

দেয়:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}

39

আপনি যদি ভাবেন যে ল্যাম্বডাস মন্দ, তবে আর পড়বেন না। অনুরোধ হিসাবে, আপনি একটি অভিব্যক্তি দিয়ে দ্রুত এবং মেমরির দক্ষ সমাধান লিখতে পারেন:

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

উপরে প্রস্তাবিত হিসাবে, দুটি লাইন ব্যবহার করা বা একটি ফাংশন লেখার সম্ভবত আরও ভাল উপায়।



30

পাইথন 3-তে, itemsপদ্ধতিটি আর কোনও তালিকা দেয় না , বরং একটি দৃশ্যে ফিরে আসে , যা একটি সেটের মতো কাজ করে। এক্ষেত্রে আপনাকে সেট ইউনিয়ন নিতে +হবে যেহেতু কনটেনেটিং কাজ করবে না:

dict(x.items() | y.items())

সংস্করণ ২.7-তে পাইথন ৩-এর মতো আচরণের জন্য, viewitemsপদ্ধতিটির জায়গায় কাজ করা উচিত items:

dict(x.viewitems() | y.viewitems())

আমি যাহাই হউক না কেন এই স্বরলিপিটি পছন্দ করি কারণ এটিকে সংক্ষিপ্তকরণের পরিবর্তে (শিরোনাম প্রদর্শন হিসাবে) সেট ইউনিয়ন অপারেশন হিসাবে ভাবা আরও স্বাভাবিক বলে মনে হয়।

সম্পাদনা:

পাইথন ৩ এর জন্য আরও কয়েকটি পয়েন্ট First প্রথম, দ্রষ্টব্য যে dict(x, **y)কৌতুকটি কীগুলি প্রবেশ না করে অজগর 3 তে কাজ করবে নাy স্ট্রিং না থাকে।

এছাড়াও, রেমন্ড হেট্টিংজারের চ্যানম্যাপ উত্তরটি বেশ মার্জিত, যেহেতু এটি একটি স্বতঃস্ফূর্ত সংখ্যক ডিকটকে যুক্তি হিসাবে গ্রহণ করতে পারে তবে ডকগুলি থেকে দেখে মনে হচ্ছে এটি ক্রমান্বয়ে প্রতিটি তল্লাশীর জন্য সমস্ত ডিক্টের একটি তালিকা দেখায়:

কোনও চাবি না পাওয়া পর্যন্ত অনুসন্ধানগুলি অন্তর্নিহিত ম্যাপিংগুলি ধারাবাহিকভাবে অনুসন্ধান করে।

আপনার অ্যাপ্লিকেশনটিতে অনেকগুলি লুকআপ থাকলে এটি আপনাকে ধীর করতে পারে:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

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


22

অপব্যবহার ম্যাথিউয়ের উত্তরের জন্য এক-প্রকাশের সমাধানের দিকে পরিচালিত করে :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

আপনি বলেছিলেন যে আপনি একটি অভিব্যক্তি চান, সুতরাং আমি lambdaএকটি নাম বাঁধতে অপব্যবহার করেছি এবং ল্যাম্বদার এক-প্রকাশের সীমাটি ওভাররাইড করতে টিপলস দিয়েছি । খিঁচুনি নির্দ্বিধায়।

আপনি যদি এটি অনুলিপি করার বিষয়ে চিন্তা না করেন তবে আপনি অবশ্যই এটি করতে পারেন:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}

22

অর্ডার সংরক্ষণ করে ইটারটুলগুলি ব্যবহার করে সাধারণ সমাধান (পরবর্তী দিকের ডিক্টগুলির প্রাধান্য রয়েছে)

import itertools as it
merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args)))

এবং এটির ব্যবহার:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}


16

যদিও এই অগভীর অভিধানের জন্য উত্তরগুলি ভাল ছিল , এখানে বর্ণিত পদ্ধতিগুলির কোনওটিই একটি গভীর অভিধানকে একীভূত করে না।

উদাহরণ অনুসরণ করুন:

a = { 'one': { 'depth_2': True }, 'two': True }
b = { 'one': { 'extra': False } }
print dict(a.items() + b.items())

কেউ এরকম কোনও কিছুর ফলাফল আশা করতে পারে:

{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }

পরিবর্তে, আমরা এটি পেয়েছি:

{'two': True, 'one': {'extra': False}}

'এক' এন্ট্রিটির অভিধানের ভিতরে আইটেম হিসাবে 'গভীরতা 2' এবং 'অতিরিক্ত' হওয়া উচিত ছিল যদি এটি সত্যই মার্জ হত।

চেইন ব্যবহার করেও কাজ করে না:

from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))

ফলাফল স্বরূপ:

{'two': True, 'one': {'extra': False}}

আরসিউইসিক যে গভীর মার্জ করেছে তা একই ফলাফল তৈরি করে।

হ্যাঁ, এটি নমুনা অভিধানগুলিকে মার্জ করার জন্য কাজ করবে তবে এগুলির কোনওটিই মার্জ করার জেনেরিক প্রক্রিয়া নয়। আমি পরে এটি আপডেট করব একবার আমি এমন একটি পদ্ধতি লিখি যা একটি সত্য সংশ্লেষ করে।


11

(কেবল পাইথন 2.7 * এর জন্য; পাইথন 3 * এর সহজ সমাধান রয়েছে))

আপনি যদি কোনও মানক পাঠাগার মডিউল আমদানি করতে বিরত না হন তবে আপনি এটি করতে পারেন

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

( or aবিটটি lambdaপ্রয়োজনীয় কারণ dict.updateসর্বদা Noneসাফল্যে ফিরে আসে ))


11

আপনি যদি পরিবর্তন করতে কিছু মনে করেন না x,

x.update(y) or x

সরল, পাঠযোগ্য, পারফরম্যান্ট। আপনি জানেন যে update() সর্বদা ফিরে আসে None, যা একটি মিথ্যা মান। সুতরাং উপরের এক্সপ্রেশনটি সর্বদা xএটি আপডেট করার পরে মূল্যায়ন করবে।

স্ট্যান্ডার্ড লাইব্রেরিতে পরিবর্তনের পদ্ধতিগুলি (যেমন .update()) Noneকনভেনশনে ফিরে আসে , সুতরাং এই প্যাটার্নগুলি সেগুলিতেও কাজ করবে। আপনি যদি এমন কোনও পদ্ধতি ব্যবহার করছেন যা এই সম্মেলনটি অনুসরণ করে না, তবে orকাজ নাও করতে পারে। তবে এর পরিবর্তে আপনি এটিকে একক প্রকাশ করতে একটি টুপল ডিসপ্লে এবং সূচক ব্যবহার করতে পারেন। প্রথম উপাদানটি যা মূল্যায়ন করে তা নির্বিশেষে এটি কাজ করে।

(x.update(y), x)[-1]

আপনার যদি xএখনও কোনও ভেরিয়েবল না থাকে তবে আপনি lambdaএকটি অ্যাসাইনমেন্ট স্টেটমেন্ট না ব্যবহার করে স্থানীয় করতে ব্যবহার করতে পারেন । এটি lambdaএকটি লেট এক্সপ্রেশন হিসাবে ব্যবহারের পরিমাণ , যা কার্যকরী ভাষাগুলির একটি সাধারণ কৌশল, তবে সম্ভবত অপ্রচলিত।

(lambda x: x.update(y) or x)({'a': 1, 'b': 2})

যদিও এটি নতুন ওয়ালরাস অপারেটরের নিম্নলিখিত ব্যবহারের চেয়ে আলাদা নয় (কেবল পাইথন ৩.৮++):

(x := {'a': 1, 'b': 2}).update(y) or x

আপনি যদি একটি অনুলিপি চান, পিইপি 448 শৈলী সবচেয়ে সহজ {**x, **y}। তবে এটি যদি আপনার (পুরানো) পাইথন সংস্করণে না পাওয়া যায় তবে লেট প্যাটার্নটি এখানেও কাজ করে।

(lambda z: z.update(y) or z)(x.copy())

(এটি অবশ্যই এর সমতুল্য (z := x.copy()).update(y) or z, তবে যদি আপনার পাইথন সংস্করণটি এর জন্য যথেষ্ট নতুন হয়, তবে পিইপি 448 শৈলী পাওয়া যাবে))


10

এখানে এবং অন্য কোথাও ধারণাগুলি আঁকতে আমি একটি ফাংশন বুঝতে পেরেছি:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

ব্যবহার (অজগর 3 এ পরীক্ষিত):

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

পরিবর্তে আপনি একটি ল্যাম্বডা ব্যবহার করতে পারেন।


10

তারিখের তালিকাভুক্ত সমাধানগুলির সাথে আমার যে সমস্যাটি রয়েছে তা হ'ল, একীভূত অভিধানে, কী "বি" এর মান 10 কিন্তু আমার চিন্তাভাবনার ক্ষেত্রে, এটি হওয়া উচিত 12 সেই আলোকে, আমি নিম্নলিখিতটি উপস্থাপন করছি:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

ফলাফল:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}

1
আপনি আগ্রহী হতে পারে cytoolz.merge_with( toolz.readthedocs.io/en/latest/... )
bli

10

এটি এত নির্বোধ যে .updateকিছুই ফেরায় না।
সমস্যাটি সমাধান করার জন্য আমি কেবল একটি সাধারণ সহায়ক ফাংশন ব্যবহার করি:

def merge(dict1,*dicts):
    for dict2 in dicts:
        dict1.update(dict2)
    return dict1

উদাহরণ:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy

10
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

এটা আপনার সমস্যা সমাধান করবে.


9

এটি একটি একক ডিক বোঝাপড়া দিয়ে করা যেতে পারে:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

আমার দৃষ্টিতে কোনও একক ক্রিয়াকলাপের প্রয়োজন নেই বলে 'একক অভিব্যক্তি' অংশের সেরা উত্তর, এবং এটি সংক্ষিপ্ত।


আমি সন্দেহ করি পারফরম্যান্স যদিও খুব ভাল হবে না; প্রতিটি ডিকের বাইরে একটি সেট তৈরি করার পরে কেবল কীগুলির সাহায্যে পুনরাবৃত্তি করার অর্থ প্রতিবারের জন্য অন্য একটি অনুসন্ধানের অর্থ (তুলনামূলকভাবে দ্রুত হলেও তবুও স্কেলিংয়ের
ক্রমটি

2
এগুলি সবই আমরা ব্যবহার করছি অজগরটির সংস্করণে। 3.5 এবং এর উপরে above ** x, ** y the সংক্ষিপ্ত অভিধান দেয়
রশিদ এমভি

9

পিইপি 572: অ্যাসাইনমেন্ট এক্সপ্রেশনসকে ধন্যবাদ পাইথন ৩.৮ প্রকাশিত হলে ( ২০ শে অক্টোবর, 2019 এর জন্য নির্ধারিত ) একটি নতুন বিকল্প থাকবে । নতুন অ্যাসাইনমেন্ট এক্সপ্রেশন অপারেটর আপনাকে ফলাফলটি অর্পণ করতে এবং এটির কল করতে এখনও ব্যবহার করতে সম্মিলিত কোডটিকে দুটি বিবৃতি পরিবর্তনের পরিবর্তে দুটি বক্তব্যকে বাদ দিয়ে পরিবর্তিত::=copyupdate

newdict = dict1.copy()
newdict.update(dict2)

প্রতি:

(newdict := dict1.copy()).update(dict2)

প্রতিটি উপায়ে অভিন্ন আচরণ করার সময়। যদি আপনাকে অবশ্যই ফলাফলটি ফেরত দিতে হয় dict( dictউপরেরটি আপনাকে পুনরায় প্রত্যাখ্যান করার জন্য বলেছিল ; উপরেরটি তৈরি করে এবং বরাদ্দ করে newdict, তবে তা ফেরত দেয় না, তাই আপনি এটি কোনও ফাংশনে আর্গুমেন্টটি পাস করার জন্য এটি ব্যবহার করতে পারবেন না, লা myfunc((newdict := dict1.copy()).update(dict2))) , তারপরে কেবল শেষটি যুক্ত করুন or newdict(যেহেতু updateপ্রত্যাবর্তন None, যা মিথ্যা, তাই এটি মূল্যায়িত হবে এবং newdictপ্রকাশের ফলাফল হিসাবে ফিরে আসবে ):

(newdict := dict1.copy()).update(dict2) or newdict

গুরুত্বপূর্ণ সতর্কতা: সাধারণভাবে, আমি এই পদ্ধতির পক্ষে পক্ষে নিরুৎসাহিত করব:

newdict = {**dict1, **dict2}

আন-প্যাক পদ্ধতির (যারা প্রথম স্থানে সাধারণ আন-প্যাক, জানে কাছে আরো স্পষ্ট হয় যা আপনি উচিত ), (এ সব ফলাফলের জন্য একটি নাম প্রয়োজন হয় না তাই এটি আরো অনেক কিছু সংক্ষিপ্ত যখন একটি অস্থায়ী যে অবিলম্বে প্রেরণ করা নির্মাণের ফাংশন বা একটি list/ এ অন্তর্ভুক্তtuple আক্ষরিক বা এর মতো অন্তর্ভুক্ত), এবং প্রায় অবশ্যই দ্রুত (সিপাইথনে) মোটামুটি সমান:

newdict = {}
newdict.update(dict1)
newdict.update(dict2)

তবে কংক্রিট ব্যবহার করে সি লেয়ারে করা হয়েছে dict এপিআই , সুতরাং কোনও গতিশীল পদ্ধতি লকউইচিং / বাঁধাই বা ফাংশন কল প্রেরণা ওভারহেড জড়িত নেই (যেখানে (newdict := dict1.copy()).update(dict2)আচরণে মূল দ্বি-লাইনারের সাথে অনিবার্যভাবে অভিন্ন, গতিশীল অনুসন্ধানের সাথে পৃথক পদক্ষেপে কাজ সম্পাদন করা হয়) / বাঁধাই / পদ্ধতির প্রার্থনা।

এটি আরও বেশি বর্ধনযোগ্য, কারণ তিনটি সংযুক্তিটি dictসুস্পষ্ট:

 newdict = {**dict1, **dict2, **dict3}

অ্যাসাইনমেন্ট এক্সপ্রেশন ব্যবহার করে যেখানে স্কেল হবে না; আপনি পেতে পারেন নিকটতম হতে হবে:

 (newdict := dict1.copy()).update(dict2), newdict.update(dict3)

বা অস্থায়ী টুপল ছাড়া None, তবে প্রতিটি Noneফলাফলের সত্যতা পরীক্ষা সহ :

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)

পারেন যার স্পষ্টত অনেক uglier, এবং আরও অকার্যকরই অন্তর্ভুক্ত (হয় একটি বরবাদ অস্থায়ী tupleএর Noneকমা বিচ্ছেদ, অথবা প্রতিটি অর্থহীন truthiness পরীক্ষার জন্য গুলি update'র Noneবিনিময়ে orবিচ্ছেদ)।

অ্যাসাইনমেন্ট এক্সপ্রেশন পদ্ধতির একমাত্র আসল সুবিধাটি ঘটে যদি:

  1. আপনার জেনেরিক কোড রয়েছে যা উভয় setএবং dictগুলি উভয়ই পরিচালনা করতে পারে (উভয়ই সমর্থন করে copyএবং updateতাই কোডটি মোটামুটিভাবে কাজ করে যেমন আপনি এটি আশা করেন)
  2. আপনি কেবল dictনিজেরাই নয়, স্বেচ্ছাচারী ডিক্ট-এর মতো অবজেক্টগুলি প্রাপ্ত করার প্রত্যাশা করছেন এবং অবশ্যই বাম হাতের ধরণ এবং শব্দার্থবিজ্ঞান সংরক্ষণ করতে হবে (কোনও সমতল দিয়ে শেষ না করে dict)। myspecialdict({**speciala, **specialb})কাজ করার সময় এটি কোনও অতিরিক্ত অস্থায়ীকে জড়িত করতে পারে dictএবং যদিmyspecialdict এর বৈশিষ্ট্যগুলি সমতলdict সংরক্ষণ করতে পারে না (উদাহরণস্বরূপ নিয়মিত dictএখন কীটির প্রথম উপস্থিতির উপর ভিত্তি করে অর্ডার সংরক্ষণ করে এবং একটি চাবির শেষ উপস্থিতির উপর ভিত্তি করে মান) আপনি চান শেষের উপর ভিত্তি করে অর্ডার সংরক্ষণ করে এমন একটিকোনও মানকে আপডেট করার সাথে সাথে একটি কী উপস্থিত হওয়াও এটিকে শেষ দিকে নিয়ে যায়), তবে শব্দার্থবিজ্ঞান ভুল হবে। যেহেতু অ্যাসাইনমেন্ট এক্সপ্রেশন সংস্করণটি নামযুক্ত পদ্ধতিগুলি ব্যবহার করে (যা সম্ভবত যথাযথভাবে আচরণ করার জন্য অতিরিক্ত বোঝা হয়ে থাকে), এটি কোনও ধরণের অস্থায়ীতা এড়িয়ে গিয়ে মূল ধরণের (এবং মূল ধরণের শব্দার্থক) সংরক্ষণ করে কখনই তৈরি করে না dict( কখনই এটি dict1ইতিমধ্যে ছিল না dict)।

8
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}

এই পদ্ধতিটি xতার অনুলিপি দিয়ে ওভাররাইট করে। যদি xকোনও ফাংশন আর্গুমেন্ট হয় তবে এটি কাজ করবে না ( উদাহরণ দেখুন )
বার্টোলো-ওট্রিট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.