繁体   English   中英

使用 Java 8 如何根据过滤条件按列表过滤和分组并转换为 Map 及其计数

[英]using Java 8 How to filter by list and group by based on filter condition and convert to Map with their count

我想将下面的 for 循环转换为 Java 8。但是在过滤状态列表和分组为一个状态和总数时遇到问题。 我试过了,但是对于每个"LIVE""DRAFT""TEST"必须循环 3 次并获得 3 个不同的地图。 是否可以使用 Java-8 进入一个循环?

其中"LIVE""DRAFT""TEST"再次是来自workflowInstance的状态组合,例如DRAFT = {"DRAFT_EDIT","DRAFT_SAVE"} 我想根据定义的这个组合将所有状态分类为 3。

Map<String, Integer> summaryMap = new HashMap<>();
int l = 0, d = 0, t = 0;

for (WorkflowInstance instance : workflowInstances) {
    if (liveStatuses.contains(instance.getStatus())) {
        summaryMap.put("LIVE", l++);
    } else if (testStatuses.contains(instance.getStatus())) {
        summaryMap.put("TEST", t++);
    } else if (draftStatuses.contains(instance.getStatus())) {
        summaryMap.put("DRAFT", d++);
    }
}

Java-8 分别用于"LIVE""DRAFT""TEST"

map.put("DRAFT", workflowInstances.stream()
     .filter(inst-> Constants.DRAFT_STATUS.contains(inst.getStatus()))
     .collect(Collectors.groupingBy(WorkflowInstance::getStatus, Collectors.counting()))
     .entrySet().stream().mapToLong(e-> e.getValue()).sum()
);

map.put("LIVE", workflowInstances.stream()
     .filter(inst-> Constants.LIVE_STATUS.contains(inst.getStatus()))
     .collect(Collectors.groupingBy(WorkflowInstance::getStatus, Collectors.counting()))
     .entrySet().stream().mapToLong(e-> e.getValue()).sum()
);

// Similar for "TEST"

我不想循环 3 次,而是想在 1 个 go 中对它们进行分类。 任何帮助,将不胜感激。

我认为您需要做的就是创建一个更复杂的分组 function ,它将getStatus转换为您想要的三种类型之一。 你可以尝试这样的事情:

Map<String, Long> summaryMap = workflowInstances.stream()
    .groupingBy(a -> {
        if (liveStatuses.contains(a.getStatus())) {
            return "LIVE";
        } else if (testStatuses.contains(a.getStatus())) {
            return "TEST";
        } else if (draftStatuses.contains(a.getStatus())) {
            return "DRAFT";
        }
     }, Collectors.counting());

无论如何,您都无法避免提取状态的类型。 为它创建一个专用方法(我想作为liveStatuses等的状态列表是 static 或实例变量。请注意,您忘记处理没有任何预定义状态与当前状态匹配的情况。在这种情况下,让我们使用"UNDEFINED"

String extractStatus(WorkflowInstance workflowInstance) {
    String status = workflowInstance.getStatus();
    if (liveStatuses.contains(status)) {
        return "LIVE";
    } else if (testStatuses.contains(status)) {
        return "TEST";
    } else if (draftStatuses.contains(status)) {
        return "DRAFT";
    }
    return "UNCATEGORIZED";                          // in case nothing is matched
}

然后使用Collectors.groupingByCollectors.counting的组合进行收集相当容易:

Map<String, Long> map = workflowInstances.stream()
    .collect(Collectors.groupingBy(                  // groups to Map
            this::extractStatus,                     // extracted status is the key
            Collectors.counting()));                 // value is a number of occurences

注意结果是Map<String, Long>如果你坚持Map<String, Integer>你需要一个额外的下游收集器使用Collectors.collectingAndThen

Map<String, Integer> map = workflowInstances.stream()
    .collect(Collectors.groupingBy(                   // groups to Map
            Foo::extractStatus,                       // extracted status is the key
            Collectors.collectingAndThen(             // value is collected ...
                    Collectors.counting(),            // ... a number of occurences
                    count -> new BigDecimal(count)    // ... as Integer from Long
                                 .intValueExact()))); // ... but might throw an exception 

如果数字超出范围,则会引发ArithmeticException 请记住, Long的范围比Integer更大。 Long -> Integer的转换方式有很多种,但原理相同。

...或使用Collectors.summingInt(e -> 1)代替@HadiJ建议的Collectors.counting的简单技巧。 它返回Integer代替:

Map<String, Integer> map = workflowInstances.stream()
    .collect(Collectors.groupingBy(this::extractStatus, Collectors.summingInt(e -> 1)));

检查此代码:我的解决方案添加一个枚举来处理不同类型的多个状态。

public static void main(String[] args) {
        List<Instance> instances = new ArrayList<>();
        instances.add(new Instance("LIVE"));
        instances.add(new Instance("TEST"));
        instances.add(new Instance("TEST"));
        instances.add(new Instance("TEST"));
        instances.add(new Instance("DRAFT"));
        instances.add(new Instance("DRAFT"));

        Map<String, Long> counts = instances.stream()
.collect(Collectors.groupingBy(a -> TemplateStatus.getStatus(a.getStatus()),Collectors.counting());

        System.out.println(counts);  //output: {DRAFT=2, TEST=3, LIVE=1}

    }



class Instance {
    public Instance(String status) {
        this.status = status;
    }

    private String status;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}

enum TemplateStatus {
    LIVE("LIVE,LIVE2"), DRAFT("DRAFT,DRAFT_2"), TEST("TEST_1,TEST");

    private List<String> status;

    TemplateStatus(String s) {
        status = Arrays.asList(s.split(","));
    }

    public static String getStatus(String s) {
        if (LIVE.status.contains(s)) return "LIVE";
        else if (TEST.status.contains(s)) return "TEST";
        else if (DRAFT.status.contains(s)) return "DRAFT";
        return "UNKNOWN";
    }
}

希望这可以帮助你

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM