質問: javaの初心者です。 以下のようなデータを保持したい場合、どのようにデータを保持し、追加していくのがいいのでしょうか。 追加の際には、「name」と「user」が一つずつ処理され、変数に貯めたいです。 name、userともにString型になります。 nameやuserに関しては可変長です。 nameが重複した際にはすでに存在しているnameのuserとして追加したいです。 ※複数のnameに対して、userが所属することもある ※name内でuserは一意になる ``` { name_1 : [user_1,user_2,user_4....user_n], name_2 : [user_1, user_5....user_n], ... : [user_1, user_10, ....user_n ], name_n : [user_3, user_5, ....user_n ] } ``` データの蓄積のイメージ(例) 1. {} 2. {name_1 : [user_1]} 3. {name_1 : [user_1,user_2]} 4. {name_1 : [user_1,user_2], name_3 : [user_4]} ご教示いただけますと幸いです。
回答: `user` がコレクションの中で一意であることを保証するためには、`Set`を使用するのが良いでしょう。 また、その`Set`が`name`毎に1つ存在することを表すのには`Map`を使用します。 そのため、基本的に`Map>`という型を使用することになるでしょう。 一番簡単な方法としては、この型をそのまま使うことです。 ``` public class Main { public static void main(final String[] args) { final Map> map = new HashMap<>(); { final SortedSet name1Users = new TreeSet<>(); name1Users.add("user_1"); map.put("name_1", name1Users); } { final SortedSet users = map.get("name_1"); users.add("user_2"); map.get("name_1").forEach(System.out::println); } { // "name_3" という key の value がなかった時(value が nullだった時)に、 // 第二引数で初期値を設定し、その値を返す final SortedSet users = map.computeIfAbsent("name_3", k -> new TreeSet<>()); users.add("user_4"); map.get("name_3").forEach(System.out::println); } } } ``` ただし、この方法だと`Map`や`Set`のメソッドを直接実行することになるため、各処理で何をやっているのかがわかりづらい場合があります。 2つ目の方法は、このコレクション型をラップした(メンバーに持つ)クラスを定義することです。 ※このようなクラスを「ファーストクラスコレクション」と呼びます ``` class UserContainer { private final Map> userMap = new HashMap<>(); public SortedSet getUsers(String name) { return userMap.getOrDefault(name, new TreeSet<>()); } public void addUser(String name, String user) { SortedSet users = userMap.computeIfAbsent(name, k -> new TreeSet<>()); users.add(user); } /** * user が所属している name の一覧を返す */ public List getNames(String user) { return userMap .entrySet() .stream() .filter(entry -> entry.getValue().contains(user)) .map(Map.Entry::getKey) .sorted() .collect(Collectors.toList()); } } ``` こちらのメリットは 1. メソッド名に意味の分かりやすい名前を付けられる 2. 上記のように`getNames()`のような処理を定義できる (毎回このような処理を使う側で書く必要がない) 等が挙げられます。 * `user` がソートされるものとして `SortedSet`(`TreeSet`)を使用していますが、ソートされている必要がなければ、`Set`(`HashSet`)を使用してください。 * Java SE 8以降を前提としてstreamを使用していますので、わからない場合は調べたり、質問したりしてください。