

python始めたばかりの初心者です。

環境:Python 2.7.6

現在複数の辞書型配列をマージしようと試みているのですが、keyが同じのため上書きされてしまい困っています。

つまり

[code]

    dic  = {'A':'1', 'B':'2'}
    dic1 = {'A':'3', 'B':'2', 'C':'4'}
    
[/code]

この2つの辞書型配列があったときに足し合わせて

[code]

    dic_rev ={'A':'1,3', 'B':'2', 'C':'4'}
    
[/code]

としたいのです。


CC BY-SA 3.0
2016-09-13T16:48:25.127
28864
2016-09-14T02:02:16.153
18779
question
python
辞書型においてkeyが重複する場合,上書きをせずに連結する方法について


「マージ」でやりたいことが不明確ですが、以下のコードで期待する結果が出せそうです。  
同じ値の場合にカンマで連結しないようにしています。

[code]

    >>> dic  = {'A':'1', 'B':'2'}
    >>> dic1 = {'A':'3', 'B':'2', 'C':'4'}
    >>> dic_rev = {}
    >>> for k in set(dic) | set(dic1):
    ...     vl = []
    ...     if k in dic:
    ...         vl.append(dic[k])
    ...     if k in dic1 and dic1[k] not in vl:
    ...         vl.append(dic1[k])
    ...     dic_rev[k] = ','.join(vl)
    ...
    >>> dic_rev
    {'A': '1,3', 'B': '2', 'C': '4'}
    
[/code]


CC BY-SA 3.0
2016-09-13T17:45:05.927
28866
2016-09-13T17:45:05.927
806
28864
answer


別解として `reduce` を使う方法などを。

[code]

    def merge_dict(d, k, v):
      if k in d:
        if d[k] != v:
          d[k] += ',' + v
      else:
        d[k] = v
      return d
    
    reduce(lambda d, (k, v): merge_dict(d, k, v), dic.items() + dic1.items(), dict())
    => {'A': '1,3', 'C': '4', 'B': '2'}
    
[/code]


CC BY-SA 3.0
2016-09-13T18:53:29.163
28867
2016-09-13T18:53:29.163
28864
answer


複数の辞書型配列の value
をマージすると、[`defaultdict`](https://docs.python.org/2/library/collections.html#collections.defaultdict)
を使用すべきだと思います。

[code]

    from collections import defaultdict
    
    def merge_dict_values(*dicts):
        r = defaultdict(set)
        for d in dicts:
            for k, v in d.iteritems():
                r[k].add(v)
        return r
    
    dic  = {'A':'1', 'B':'2'}
    dic1 = {'A':'3', 'B':'2', 'C':'4'}
    dic_merged = merge_dict_values(dic, dic1)
    print dic_merged
    # defaultdict(<type 'set'>, {'A': set(['1', '3']), 'C': set(['4']), 'B': set(['2'])})
    
[/code]

こうして、各辞書型配列を合併しました。あとは、`set` 型の値を連結して、文字列にします。

[code]

    dic_rev = {k: ','.join(v) for k, v in dic_merged.iteritems()}
    print dic_rev
    # {'A': '1,3', 'C': '4', 'B': '2'}
    
[/code]

上記の解決には、`set` を使いましたから、連結した値の順序を保証できません。

各パラメーターの順序と同じしたいなら、以下のような、`list` で格納すべきです。

[code]

    def merge_dict_values(*dicts):
        r = defaultdict(list)     # list に変更し
        for d in dicts:
            for k, v in d.iteritems():
                if v not in r[k]: # この値がない場合追加します
                    r[k].append(v)
        return r
    
[/code]


CC BY-SA 3.0
2016-09-14T02:02:16.153
28869
2016-09-14T02:02:16.153
18621
28864
answer