以下の?????を埋めよ。但し文字数の指定はない。解答はいくつかあると思うが後日。
>>> d1 = {'a':1, 'b':2, 'c':3}Pythonクイズ(辞書の非破壊的操作) - プログラミング日記
>>> d2 = {'c':4, 'd':5, 'e':6}
>>> print ?????
{'a': 1, 'c': 4, 'b': 2, 'e': 6, 'd': 5}
>>> d1
{'a': 1, 'c': 3, 'b': 2}
>>> d2
{'c': 4, 'e': 6, 'd': 5}
>>> d1.update(d2)
>>> d1
{'a': 1, 'c': 4, 'b': 2, 'e': 6, 'd': 5}
>>> d2
{'c': 4, 'e': 6, 'd': 5}
Squeak Smalltalk で同じことをするならこんな感じでしょうか。
| d1 d2 | d1 := {#a->1. #b->2. #c->3} as: Dictionary. d2 := {#c->4. #d->5. #e->6} as: Dictionary. d1, d2. "=> a Dictionary(#a->1 #b->2 #c->4 #d->5 #e->6 ) " d1. "=> a Dictionary(#a->1 #b->2 #c->3 ) " d2. "=> a Dictionary(#c->4 #d->5 #e->6 ) " d1 addAll: d2. d1. "=> a Dictionary(#a->1 #b->2 #c->4 #d->5 #e->6 ) " d2. "=> a Dictionary(#c->4 #d->5 #e->6 ) "
Smalltalk では辞書(a Dictionary)はアソシエーション(an Association。key->value)を要素とするセット(a Set。順序なし、重複を許さないコレクション)として実現されているので、配列などの他のコレクションと同じように Collection>>#, をコールして非破壊的に結合できます。
ちなみに Collection>>#, の定義はこんな感じです。
Collection >> , aCollection
^self copy addAll: aCollection; yourself
なんてことはないですね。複製を作って #addAll:、つまり破壊的な結合(上の実行例でも使っています)をしているだけ。なお、Dictionary>>#addAll: はこんなふうな定義なので、
Dictionary >> addAll: aKeyedCollection aKeyedCollection == self ifFalse: [ aKeyedCollection keysAndValuesDo: [:key :value | self at: key put: value]]. ^aKeyedCollection
キーが同一のものがレシーバに存在する場合は上書きされます。
これを踏まえて Python で同様のことを試そうとすると…
>>> d1 = {'a':1, 'b':2, 'c':3} >>> d2 = {'c':4, 'd':5, 'e':6} >>> d1 + d2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'dict' and 'dict' >>>
どうやら同じ「辞書」つながりと甘く見ていたら、少々勝手が違うみたいです(当たり前w)。ならば、複製して破壊的な結合をすればよいのでは…と、
>>> d1.copy().update(d2) >>>
してみたのですが update() は返値を持たないので結果を出力してくれず、このお題には向きません。もっともこうした事態は Smalltalk でも #addAll: がレシーバを返さないことからもあらかじめ想定しておくべきでした。orz
Smalltalk でならここで ; yourself (「;」は直前のメッセージ式のレシーバにメッセージをたたみかけて送るための構文で、#yourself はレシーバを返すだけのメソッド。上の Collection>>#, の定義でも使われています)の出番なのですが、Python の OOP はメッセージングパラダイムではないので、こうした機能は無いはずです(じゃあメッセージングパラダイムの Ruby にはあるかっていうと無いんですけれども…^^;)。
しかたがないので、富豪的に。
>>> dict(d1.items() + d2.items()) {'a': 1, 'c': 4, 'b': 2, 'e': 6, 'd': 5}