リストを項目ごとに集計するときのデータオブジェクトの使い方
irofさんのブログを見て、自分ならどう書くかなーと思ったので、読み進める前に書いてみました。
その結果、本題のアルゴリズムとは全然関係ないところで疑問を持ったので、グデグデとメモします。
元エントリ
irofさんによる元エントリはこちら。
- リストを項目ごとに集計する http://d.hatena.ne.jp/irof/20111203/p1
{code, 名前, 数値} というデータ構造のリストについて、code(idみたいなものです)をキーに数値を集計したい。このとき、Javaでどう書くか?というお話です。
書いてみた
import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; class Data { String code; String name; int value; Data() { } Data(String initCode, String initName, int initValue) { code = initCode; name = initName; value = initValue; } } public class SummaryCount { protected List<Data> getTestData() { List<Data> returnList = new ArrayList<Data>(); returnList.add(new Data("A01", "hoge", 100)); returnList.add(new Data("A01", "piyo", 200)); returnList.add(new Data("A02", "hoge", 300)); returnList.add(new Data("A03", "hoge", 400)); returnList.add(new Data("A03", "piyo", 500)); return returnList; } public static void main(String[] args) { SummaryCount sc = new SummaryCount(); List<Data> testDataList = sc.getTestData(); Map<String, Integer> summaryMap = sc.getSummaryByCode(testDataList); sc.showResult(summaryMap); } /** * 各Dataのcodeをキーとしてvalueを集計します。 * * @param dataList * @return */ protected Map<String, Integer> getSummaryByCode(List<Data> dataList) { Map<String, Integer> map = new HashMap<String, Integer>(); for (Data data : dataList) { if (map.containsKey(data.code)) { map.put(data.code, map.get(data.code) + data.value); } else { map.put(data.code, data.value); } } return map; } protected void showResult(Map<String, Integer> tempMap) { Set<String> set = tempMap.keySet(); for (String key : set) { System.out.println(key + ", " + tempMap.get(key)); } } }
思ったこと
その1
コンパイラは、かならずしも式を左から右へ評価するとは限りません。そのため、=オペレータの右辺と左辺で同じ式を評価してはいけません。
しかし、argumentが評価されてから、メソッドの結果が評価されるという順序は、さすがに保証されているだろうと思ってこう書きました。
map.put(data.code, map.get(data.code) + data.value);
これは、いいんですよね?? ちなみに、もしダメだったら、こう書かなければいけませんが・・・。
int i = map.get(data.code);
map.put(data.code, i + data.value)
さすがに大丈夫でしょう、はい。。。
その2
集計に使うデータ構造として、irofさんはMap
自分も最初同じように書いたのですが、データオブジェクトの使い方について疑問を持ったので、Map
集計中の関心の対象は、キーであるcodeフィールドと、valueフィールドです。では、valueフィールドにどんどんデータを足しこんでいく集計の間、関心外のフィールド、つまりnameの値は、どうなるでしょうか。ここでは特に設定していないため、不定です。そのことに違和感がありました。
こういった場合、集計用のデータオブジェクトを新たに定義するべきですか? そこまでするのは面倒くさいとき、Data型を使ってもよいものなのでしょうか? 自分が書いたように、適宜、集計用のCollectionを持つと、やっぱり分かりづらいでしょうか。
これは、人によって答えが違うかもしれません。
余談
Javaで書く限り、そんなにバリエーションはないだろうと高を括っていたのですが、コメント欄に貼られたxuwei-kさんの回答(https://gist.github.com/1429171)を見て愕然としました。Scalaを習得すればあんな世界観を獲得できるのか! 凄い!
また、ひしだまさんの記事も、勉強になりました。