多次元配列テーブルデータを Python の reduce() を使って変換する方法について


自分はよく PHP で以下のようにしてデータベースから取得したレコードの変換を行います。

[code]

    <?php
    
    $list = array(
        array("GROUP" => "A", "NAME" => "りんご", "COUNT" => 1),
        array("GROUP" => "A", "NAME" => "ゴリラ", "COUNT" => 2),
        array("GROUP" => "B", "NAME" => "ラッパ", "COUNT" => 3),
    );
    
    $convert_list = array_reduce($list, function($result, $row) {
      if (!key_exists($row["GROUP"], $result)) {
        $result[$row["GROUP"]] = array();
      }
    
      $result[$row["GROUP"]][] = $row;
      return $result;
    }, array());
    
    var_dump($convert_list);
    
[/code]

結果は以下のようになります。

[code]

    array(2) {
      ["A"]=>
      array(2) {
        [0]=>
        array(3) {
          ["GROUP"]=>
          string(1) "A"
          ["NAME"]=>
          string(9) "りんご"
          ["COUNT"]=>
          int(1)
        }
        [1]=>
        array(3) {
          ["GROUP"]=>
          string(1) "A"
          ["NAME"]=>
          string(9) "ゴリラ"
          ["COUNT"]=>
          int(2)
        }
      }
      ["B"]=>
      array(1) {
        [0]=>
        array(3) {
          ["GROUP"]=>
          string(1) "B"
          ["NAME"]=>
          string(9) "ラッパ"
          ["COUNT"]=>
          int(3)
        }
      }
    }
    
[/code]

これと同様の変換をを Python の `reduce()`（ないし別の方法）で行うことはできませんでしょうか。




reduceを使う方法もご紹介します。

[code]

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import sys
    if sys.version_info[0] >= 3:
        from functools import reduce
    from pprint import pprint as pp
    
    lst = [{"GROUP": "A", "NAME": u"りんご", "COUNT": 1},
           {"GROUP": "A", "NAME": u"ゴリラ", "COUNT": 2},
           {"GROUP": "B", "NAME": u"ラッパ", "COUNT": 3}, ]
    
    def func(result, row):
        if not row["GROUP"] in result:
            result[row["GROUP"]] = []
    
        result[row["GROUP"]].append(row)
        return result
    
    pp(reduce(func, lst, {}))
    
[/code]

結果:

[code]

    {'A': [{'COUNT': 1, 'GROUP': 'A', 'NAME': 'りんご'},
           {'COUNT': 2, 'GROUP': 'A', 'NAME': 'ゴリラ'}],
     'B': [{'COUNT': 3, 'GROUP': 'B', 'NAME': 'ラッパ'}]}
    
[/code]

Pythonは複数行の無名関数が書けないので、一度関数(func)を定義しています。  
（関数を定義せずとも内包表記で記述できそうですが、可読性は低下すると思います）  
関数内での処理の流れは、ご質問のコードと同じです。

また、最初にPythonのバージョン確認と (python 3以上であれば) reduceをimportする処理をしています。これはPython
3.0以上ではreduceが組み込み関数ではなくfunctoolsモジュールに移動しているためです。結果はPython
3.4のものですが、2.7でも上記コードは実行可能です。

