マップを作成して後で変換する代わりに、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回繰り返すことを避け、パフォーマンスを向上させることはできますか?
私はあなたの要件が何であるかはわかりませんが、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());
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