简体   繁体   English

用于按输入分组的通用 java.util.function.Function

[英]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.

相关问题 Java.util.function.Function带参数 - Java.util.function.Function with parameter 将java.util.function.Function转换为Interface - Cast java.util.function.Function to Interface 关于Java泛型和java.util.function.Function设计的问题 - Question about Java generics and design of java.util.function.Function 实现java.util.function.Function时是否需要检查空输入<T,R> - Do I need to check for null input when implementing java.util.function.Function<T,R> 将 java.util.function.Function 定义为 ZA81259CEF8E5559C6297DF1D4 - Defining java.util.function.Function as static final Java 8:用于将Java.util.function.Function实现为Lambda表达式的语法 - Java 8: Syntax for Implementing java.util.function.Function as a Lambda Expression 使用java.util.function.Function实现Factory Design Pattern - use java.util.function.Function to implement Factory Design Pattern 在硒中发生错误“java:无法访问 java.util.function.Function 的 java.util.function.Function 类文件未找到” - error occurred "java: cannot access java.util.function.Function class file for java.util.function.Function not found " in selenium 从java.util.function.Function获取方法名称 - Get the method name from a java.util.function.Function 找不到java.util.function.Function的类文件 - Resolve Class file for java.util.function.Function not found
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM