gpt4 book ai didi

java - 使用stream()collect()groupingBy()和reducing()的多级映射

转载 作者:太空宇宙 更新时间:2023-11-04 12:13:21 24 4
gpt4 key购买 nike

我设法写了Collector.groupingBy(Function, groupingBy(classifier, toList())

Map<String, Map<Person.Sex, List<Person>>> groupByYearThenSex = personList.stream().collect(
groupingBy(p ->{
if(p.getYear() > 2015) return "New members";
else if(p.getYear() < 2009) return "Senior members";
else return "Normal members";
},
groupingBy(Person::getSex)
)
);
groupByYearThenSex.forEach((String y, Map<Person.Sex, List<Person>> m) ->{
System.out.println("\n" + y);
m.forEach((Person.Sex s, List<Person> p) -> {
System.out.println(" " + s);
p.forEach((Person prsn) -> {
System.out.println(" " + prsn.toString());
});

});
});

对应的结果是:

New members

MALE
Person{name: Gawel, age: 23, sex: MALE}

Normal members

MALE
Person{name: Patryk, age: 34, sex: MALE}
Person{name: Pawel, age: 21, sex: MALE}
Person{name: Bolek, age: 12, sex: MALE}
Person{name: Lolek, age: 12, sex: MALE}
FEMALE
Person{name: Jola, age: 70, sex: FEMALE}
Person{name: Ala, age: 25, sex: FEMALE}

Senior members

FEMALE
Person{name: Iwona, age: 34, sex: FEMALE}
Person{name: Oliwia, age: 17, sex: FEMALE}

现在我正在尝试生成仅列出最旧成员的多级 map ,如下所示:

New members

MALE
Person{name: Gawel, age: 23, sex: MALE}

Normal members

MALE
Person{name: Patryk, age: 34, sex: MALE}
FEMALE
Person{name: Jola, age: 70, sex: FEMALE}

Senior members

FEMALE
Person{name: Iwona, age: 34, sex: FEMALE}

下面的代码不起作用。我得到“推断变量 RR 具有不兼容的边界错误,我认为 Function<R,RR> => collectingAndThen(reducing(), Optional) 。有什么方法可以减少人员流以获取最旧的人员并获得上面的输出?

Map<String, Map<Person.Sex, List<Person>>> groupByYearThenSexOldest = personList.stream().collect(
groupingBy(p ->{
if(p.getYear() > 2015) return "New members";
else if(p.getYear() < 2009) return "Senior members";
else return "Normal members";
},
groupingBy(Person::getSex, collectingAndThen(
reducing((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2),
Optional::get)
)
)
);

最佳答案

问题出在 map 的类型参数上。它应该给你一个 Map<String, Map<Person.Sex, Person>>而不是Map<String, Map<Person.Sex, List<Person>>>因为您正在减少列表。

但是你可以结合第二个groupingBy收集器 maxBycollectingAndThen :

groupingBy(Person::getSex, collectingAndThen(maxBy(Comparator.comparingInt(Person::getAge)), Optional::get)
有时,如果您需要按多个字段进行分组,则可以使用对字段进行分组的列表(假设它们具有适当的 equals 和 hashcode 方法)。例如:

Function<Person, String> groupingYear = p -> {
if (p.getYear() > 2015) return "New members";
else if (p.getYear() < 2009) return "Senior members";
else return "Normal members";
};

Map<Object, Optional<Person>> map2 =
personList.stream()
.collect(groupingBy(p -> Arrays.asList(groupingYear.apply(p), p.getSex()), maxBy(Comparator.comparingInt(Person::getAge))));

给出:

[Normal members, MALE] => Optional[Person{name='Patryk', age=34, sex=MALE}]
[Senior members, FEMALE] => Optional[Person{name='Iwona', age=34, sex=FEMALE}]
[Normal members, FEMALE] => Optional[Person{name='Jola', age=70, sex=FEMALE}]
[New members, MALE] => Optional[Person{name='Gawel', age=23, sex=MALE}]

但是您可以从使用 toMap 开始收集器并比较当 2 个值分组在一起时您提供的合并函数中的年龄:

Map<Object, Person> map =
personList.stream()
.collect(toMap(p -> Arrays.asList(groupingYear.apply(p), p.getSex()),
p -> p,
(p1, p2) -> {
if(p1.getAge() > p2.getAge()) return p1;
else return p2;
},
HashMap::new));

您有一个Object作为您 Map 中的关键(真正的类型很糟糕而且写起来很长),但是你可以做的是创建一个专用的类 MemberStatusAndSex组合两个属性(而不是 List - 不要忘记为此类实现 equals 和 hashcode),并获得 Map<MemberStatusAndSex, Person>在最后。

关于java - 使用stream()collect()groupingBy()和reducing()的多级映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39665281/

24 4 0