web-dev-qa-db-ja.com

Javaストリームはフィールドにカウントを収集します

マップを作成して後で変換する代わりに、Collectors.groupingBy()Collectors.counting()を使用してカスタムオブジェクトのフィールドにカウントすることは可能ですか?.

次のようなユーザーのリストがあります。

public class User {
    private String firstName;
    private String lastName;
    // some more attributes

    // getters and setters
}

同じ姓名を持つすべてのユーザーをカウントしたい。したがって、次のようなカスタムオブジェクトがあります。

public static class NameGroup {
    private String firstName;
    private String lastName;
    private long count;

    // getters and setters
}

これを使用して名前グループを収集できます:

List<NameGroup> names = users.stream()
        .collect(Collectors.groupingBy(p -> Arrays.asList(p.getFirstName(), p.getLastName()), Collectors.counting()))
        .entrySet().stream()
        .map(e -> new NameGroup(e.getKey().get(0), e.getKey().get(1), e.getValue()))
        .collect(Collectors.toList());

このソリューションでは、ユーザーを最初にマップにグループ化し、後でそれをカスタムオブジェクトに変換する必要があります。すべての名前を直接nameGroup.countにカウントして、リスト(またはマップ)を2回繰り返すことを避け、パフォーマンスを向上させることはできますか?

6
Samuel Philipp

私はあなたの要件が何であるかはわかりませんが、NameGroupクラスを変更して、姓名の代わりにUserクラスを受け入れるようにしました。これにより、リストの中間ストリームとユーザーのストリームから値を選択する必要がなくなりました。しかし、それでも地図が必要です。

      List<NameGroup> names =
            users.stream().collect(Collectors.groupingBy(p -> p,Collectors.counting()))
                          .entrySet().stream()
                          .map(e -> new NameGroup(e.getKey(), e.getValue())).collect(
                              Collectors.toList());
0
WJS
public static class NameGroup {
    // ...
    @Override
    public boolean equals(Object other) {
        final NameGroup o = (NameGroup) other;
        return firstName.equals(o.firstName) && lastName.equals(o.lastName);
    }
    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName);
    }
    @Override
    public String toString() {
        return firstName + " " + lastName + " " + count;
    }
}

public static void main(String[] args) throws IOException {
    List<User> users = new ArrayList<>();
    users.add(new User("fooz", "bar"));
    users.add(new User("fooz", "bar"));
    users.add(new User("foo", "bar"));
    users.add(new User("foo", "bar"));
    users.add(new User("foo", "barz"));
    users.stream()
        .map(u -> new NameGroup(u.getFirstName(), u.getLastName(), 1L))
        .reduce(new HashMap<NameGroup, NameGroup>(), (HashMap<NameGroup, NameGroup> acc, NameGroup e) -> {
            acc.compute(e, (k, v) -> v == null ? e : new NameGroup(e.firstName, e.lastName, e.count + acc.get(e).count));
            return acc;
        }, (a, b) -> {
            b.keySet().forEach(e -> a.compute(e, (k, v) -> v == null ? e : new NameGroup(e.firstName, e.lastName, e.count + a.get(e).count)));
            return a;
        }).values().forEach(x -> System.out.println(x));
}

これは出力されます

fooz bar 2
foo barz 1
foo bar 2
0
w4bo