Map を走査する
キーで回すと、同じ場所を 2 回引くことになる
Map の中身を全部見たいとき、まず思いつくのはキーの一覧を回す書き方です。
Java
for (String day : visits.keySet()) {
System.out.println(day + " は " + visits.get(day) + " 人");
}動きますが、keySet() からキーを 1 つ取り出すたびに、get(day) でもう一度同じ場所を探しに行っています。キーと値の両方を使う処理なら、はじめからペアで受け取るほうが素直です。
その役をするのが entrySet() で、キーと値をひとまとめにした Map.Entry を順に返します。
Java
import java.util.LinkedHashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) {
Map<String, Integer> visits = new LinkedHashMap<>();
visits.put("mon", 12);
visits.put("tue", 8);
for (Map.Entry<String, Integer> e : visits.entrySet()) {
System.out.println(e.getKey() + " / " + e.getValue());
}
}
}e.getKey() でキー、e.getValue() で値が取れます。値しか使わないなら values() を回す手もありますが、片方だけで足りる場面は意外と少ないものです。
入れた順に出てこないと困る
ここが Map の走査でいちばん引っかかるところです。HashMap は取り出す順番を保証しません。put した順に並ぶこともあれば、まったく違う順で出てくることもあり、こちらからは決められません。
順番を守ってほしいなら LinkedHashMap を使います。
Java
Map<String, Integer> visits = new LinkedHashMap<>(); // put した順に出てくる
Map<String, Integer> ranked = new TreeMap<>(); // キーの昇順に並ぶ使い方はどちらも HashMap と同じで、new するクラスを差し替えるだけです。左辺の型は Map のまま変えません。表示や集計の結果を毎回そろえたい場面では、迷わず LinkedHashMap を選んでください。
つまずくところ
Map.Entry は Map の中に入れ子で定義されている型です。import java.util.Map; を書いておけば Map.Entry<String, Integer> と書けます。java.util.Map.Entry まで import すれば Entry<String, Integer> と短くできますが、最初は入れ子のまま書くほうが迷いません。
もう 1 つ、走査している最中に put や remove で中身を変えると ConcurrentModificationException が飛びます。entrySet() が返すのは中身のコピーではなく、Map をそのまま覗いている窓だからです。読むだけのループにしておけば起きません。
課題では、順番が保証される Map を作り、ペアを 1 つずつ取り出しながら値を集計します。Map.Entry の型を書くところで手が止まりやすいので、上の例の書き方をよく見てから始めてください。
要件
- クラス名は
Solution、メソッド名はtotalValue(引数なし、戻り値int) にすること java.util.LinkedHashMap<String,Integer>を使い、apple=100banana=80cherry=200の順にputすることmap.entrySet()をfor-eachで走査し、e.getValue()をsumに足し合わせてreturnすること
入出力例
totalValue() → 380