[英]Generic java.util.function.Function for Grouping as per input
I have class Foo which has some field and I want to group them to Map<Object,List<Foo>>
by fields as follow:我有一个 Foo 类,它有一些字段,我想按字段将它们分组到Map<Object,List<Foo>>
,如下所示:
class Foo {
private String cassette;
private List<String> organ; //not able to group on List<String>
private LocalDate date;
//getter setter toString
}
enum Group{
CASSETTE,
ORGAN,
DATE
}
I have a switch case for Grouping by java.util.function.Function
for Collectors.groupingBy()
as follow:我有一个按java.util.function.Function
for Collectors.groupingBy()
分组的开关案例,如下所示:
Function<Foo, Object> keyCriteria;
Group groupBy = Group.values()[1];//ordinal
switch (groupBy) {
case CASSETTE:
keyCriteria = p -> p.getCassette();
break;
case DATE:
keyCriteria = p -> p.getDate();
break;
case ORGAN:
keyCriteria = p -> p.getOrgan(); //facing problem while grouping with List<String>
break;
default:
keyCriteria = p -> p.getCassette();
}
Map<Object, List<Foo>> mapByCriteria = fooList.stream()
.collect(Collectors.groupingBy(keyCriteria));
System.out.println(mapByCriteria);
Everything works fine except case ORGAN:
除了case ORGAN:
一切正常case ORGAN:
Result getting:结果得到:
{[Lung, Liver]=[Foo [cassette=1A, organ=[Lung, Liver], date=2020-01-13]], [Liver]=[Foo [cassette=2A, organ=[Liver], date=2020-01-15]]} {[Lung, Liver]=[Foo [cassette=1A,organ=[Lung, Liver], date=2020-01-13]], [Liver]=[Foo [cassette=2A,organ=[Liver], date =2020-01-15]]}
Expected result:预期结果:
{Liver=[Foo [cassette=1A, organ=[Lung, Liver], date=2020-01-13], Foo [cassette=2A, organ=[Liver], date=2020-01-15]], Lung=[Foo [cassette=1A, organ=[Lung, Liver], date=2020-01-13]]} {Liver=[Foo [cassette=1A,organ=[Lung, Liver], date=2020-01-13], Foo [cassette=2A,organ=[Liver], date=2020-01-15]], 肺=[Foo [盒=1A,器官=[肺,肝],日期=2020-01-13]]}
Achieved expected result by work around following:通过解决以下问题实现了预期结果:
Map<Object, List<Foo>> collect = fooList.stream()
.flatMap(f -> f.getOrgan().stream().map(o -> new SimpleEntry<>(o, f))).collect(Collectors
.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
I'm looking for a switch
case and Generic
solution.我正在寻找switch
盒和Generic
解决方案。
You can not handle fundamentally different operations, like a plain mapping and a flattening, with the same code.您无法使用相同的代码处理根本不同的操作,例如普通映射和展平。 You have to handle the special case specially:您必须特别处理特殊情况:
public static Map<String, List<Foo>> mapByCriteria(List<Foo> fooList, Group criteria) {
Function<Foo, String> simpleKeyCriteria;
switch(criteria) {
case CASSETTE: simpleKeyCriteria = Foo::getCassette; break;
case DATE: simpleKeyCriteria = p -> p.getDate().toString(); break;
case ORGAN:
return fooList.stream()
.flatMap(foo -> foo.getOrgan().stream()
.map(organ -> new AbstractMap.SimpleEntry<>(organ, foo)))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
default:
throw new AssertionError(criteria);
}
return fooList.stream().collect(Collectors.groupingBy(simpleKeyCriteria));
}
In principle, it would possible to share more common operations, by splitting the stream statement into parts, but it would produce even more code while the only common code is fooList.stream()
.原则上,通过将流语句拆分为多个部分,可以共享更多通用操作,但它会产生更多代码,而唯一通用代码是fooList.stream()
。 So in this specific case, this is no win.因此,在这种特定情况下,这不是胜利。 But for completeness:但为了完整性:
public static Map<String, List<Foo>> mapByCriteria(List<Foo> fooList, Group criteria) {
Stream<Foo> stream = fooList.stream(); // imagine more chained common operations
Function<Foo, String> simpleKeyCriteria = null;
Collector<Foo, ?, Map<String, List<Foo>>> collector = null;
switch(criteria) {
case CASSETTE: simpleKeyCriteria = Foo::getCassette; break;
case DATE: simpleKeyCriteria = p -> p.getDate().toString(); break;
case ORGAN: collector = Collectors.flatMapping(
foo -> foo.getOrgan().stream()
.map(organ -> new AbstractMap.SimpleEntry<>(organ, foo)),
Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
default:
throw new AssertionError(criteria);
}
if(collector == null) collector = Collectors.groupingBy(simpleKeyCriteria);
return stream.collect(collector);
}
This bears absolutely no code duplication, but as demonstrated, is not necessarily a win over accepting small code duplication.这绝对没有代码重复,但正如所展示的那样,不一定是接受小代码重复的胜利。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.