තනි ප්රකාශනයකින් පයිතන් ශබ්දකෝෂ දෙකක් ඒකාබද්ධ කරන්නේ කෙසේද?
ශබ්ද කෝෂ සඳහා x
සහ y
, z
එය shallowly සිට අගයන් ශබ්ද කෝෂය ඒකාබද්ධ බවට පත් 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)
Python 3.9.0a4 හෝ ඊට වැඩි (අවසාන නිකුතුව දිනය දළ වශයෙන් ඔක්තෝබර් 2020): පී-584 , මෙහි සාකච්ඡා , මේ සරල කිරීමට ක්රියාත්මක කරන ලදී:
z = x | y # NOTE: 3.9+ ONLY
පැහැදිලි කිරීම
ඔබට නියෝග දෙකක් ඇති බවත්, මුල් නියෝග වෙනස් නොකර ඒවා නව නියෝගයකට ඒකාබද්ධ කිරීමට ඔබට අවශ්ය බවත් පවසන්න:
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
අපේක්ෂිත ප්රති result ලය වනුයේ නව ශබ්ද කෝෂයක් ( z
) ඒකාබද්ධ කළ අගයන් සමඟ ලබා ගැනීම සහ දෙවන ආ ict ාවේ අගයන් මුල සිට නැවත ලිවීමයි.
>>> z
{'a': 1, 'b': 3, 'c': 4}
මේ සඳහා, නව වාග් රීතිය යෝජනා පී.ඊ.පී. 448 සහ Python 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, PEP 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
අණපනත් a
වලට වඩා ප්රමුඛත්වය ගනී f
.
වෙනත් පිළිතුරු පිළිබඳ විවේචන
කලින් පිළිගත් පිළිතුරෙන් ඔබ දකින දේ භාවිතා නොකරන්න:
z = dict(x.items() + y.items())
පයිතන් 2 හි, ඔබ එක් එක් ආ ict ාව සඳහා මතකයේ ලැයිස්තු දෙකක් සාදයි, මතකයේ තුන්වන ලැයිස්තුවක් සාදන්න, පළමු දෙකේ දිගට සමාන දිගකින් යුක්ත වන අතර ඉන්පසු ලැයිස්තු තුනම ඉවතලන්න. පයිතන් 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()
පයිතන් 2.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
ඉදිකිරීම්කරු භාවිතා කරන අතර එය ඉතා වේගවත් හා මතක කාර්යක්ෂම වේ (අපගේ පියවර දෙකේ ක්රියාවලියට වඩා මදක් වැඩි ය) නමුත් මෙහි සිදුවන්නේ කුමක්ද යන්න ඔබ හරියටම නොදන්නේ නම් (එනම්, දෙවන ආ ict ාව ප්රධාන වචන තර්ක ලෙස සම්මත වේ. ඉදිකිරීම්කරු), කියවීමට අපහසුය, එය අපේක්ෂිත භාවිතය නොවේ, එබැවින් එය පයිතොනික් නොවේ.
ජැන්ගෝ හි භාවිතයට පිළියම් යෙදීම පිළිබඳ උදාහරණයක් මෙන්න .
ඩික්ස් යනු හැෂ් කළ හැකි යතුරු (උදා: ශීත කළ කට්ටල හෝ ටුපල්) ගැනීමට අදහස් කරන නමුත් යතුරු නූල් නොවන විට මෙම ක්රමය පයිතන් 3 හි අසමත් වේ.
>>> c = dict(a, **b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
සිට තැපැල් ලැයිස්තුව ගයිඩෝ වෑන් Rossum, භාෂාව නිර්මාතෘ, මෙසේ ලිවීය:
({}, ** {1: 3}) නීති විරෝධී යැයි ප්රකාශ කිරීම ගැන මම සතුටු වෙමි, මන්ද එය ** යාන්ත්රණය අනිසි ලෙස භාවිතා කිරීමකි.
හා
පෙනෙන විදිහට (x, ** y) "x.update (y) අමතන්න සහ ආපසු x" සඳහා "සිසිල් හැක්" ලෙස ගමන් කරයි. පුද්ගලිකව මම එය සිසිල් වලට වඩා පහත් කොට සලකමි.
කියවීමට ඇති අරමුණු සඳහා අණපනත් නිර්මාණය කිරීම සඳහා අපේක්ෂිත භාවිතය වන්නේ මගේ අවබෝධය (මෙන්ම භාෂාවේ නිර්මාතෘගේ අවබෝධය ) dict(**y)
, උදා:
dict(a=1, b=10, c=11)
වෙනුවට
{'a': 1, 'b': 10, 'c': 11}
අදහස් වලට ප්රතිචාර
ගයිඩෝ කුමක් dict(x, **y)
පැවසුවද, එය dt පිරිවිතරයන්ට අනුකූල වේ. පයිතන් 2 සහ 3 යන දෙකටම වැඩ කරයි. මෙය ක්රියා කරන්නේ යතුරු යතුරු සඳහා පමණක් වන අතර එය මූලික වචන පරාමිතීන් ක්රියා කරන ආකාරයෙහි සෘජු ප්රතිවිපාකයකි. මෙම ස්ථානයේ ** ක්රියාකරු භාවිතා කිරීම ද යාන්ත්රණය අනිසි ලෙස භාවිතා කිරීමක් නොවේ, ඇත්ත වශයෙන්ම ** නිර්මාණය කර ඇත්තේ හරියටම නියමයන් මූලික වචන ලෙස සම්මත කිරීම සඳහා ය.
යතුරු නූල් නොවන විට නැවතත් 3 සඳහා එය ක්රියා නොකරයි. ව්යංග ඇමතුම් කොන්ත්රාත්තුව නම් නාම අවකාශයන් සාමාන්ය විධානයන් ගන්නා අතර පරිශීලකයින් විසින් සම්මත කළ යුත්තේ වචන පද පමණක් වන වචන පමණි. අනෙක් සියලුම ඇමතුම්කරුවන් එය බලාත්මක කළහ. 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 සඳහා තවමත් කියවිය හැකි විසඳුම වේ. කියවීමේ හැකියාව ගණනය කෙරේ.
මගේ ප්රතිචාරය: 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
හෝ පයිතන් 2.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 හි ය
පයිතන් 2.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