簡體   English   中英

如何使用Java 8進行分組和收集?

[英]How to groupBy and Collect with Java 8?

我有一個元素列表,將其稱為“關鍵字”,如下所示:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}

問題是每一天都有一個關鍵字。 例如:

Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.1", metricDay="11/11/1999", position=109}
Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.3", metricDay="12/11/1999", position=108}
Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.2", metricDay="13/11/1999", position=99}
Keyword{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", price="0.6", metricDay="13/11/1999", position=5}
Keyword{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", price="0.1", metricDay="14/11/1999", position=4}
Keyword{id=3, name="kw3", owner="Josh", createdTime="13/12/1992", price="0.1", metricDay="13/11/1999", position=8}

然后,從該列表中,我想創建一個新列表,將來自所有不同日期的所有指標合並到一個列表中。 首先,我創建了一個像這樣的類:

public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 

我要存檔的是從第一個列表轉到這樣的結構:

public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}

我期望的示例:

KeywordMerged{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", metricList=[KeywordMetric{price=0.1,metricDay="11/11/1999",position=109},KeywordMetric{price=0.3,metricDay="12/11/1999",position=108},KeywordMetric{price=0.2,metricDay="13/11/1999",position=99}]
KeywordMerged{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", metricList=[KeywordMetric{price=0.6,metricDay="13/11/1999",position=5},KeywordMetric{price=0.1,metricDay="14/11/1999",position=4}]
KeywordMerged{id=3, name="kw3", owner="Josh", createdTime="13/12/1992", metricList=[KeywordMetric{price=0.1,metricDay="13/11/1999",position=8}]

我知道如何使用許多循環和可變變量來執行此操作,但是我不知道如何使用流和lambda操作來執行此操作。 我可以使用ID將所有相關關鍵字分組:

Map<Long, List<Keyword>> kwL = kwList.stream()
                    .collect(groupingBy(Keyword::getId))

而且我知道使用.forEach()可以遍歷該Map,但無法弄清楚如何使流的collect()方法從List傳遞到KeywordMerged。

您可以嘗試使用Collectors.toMap(...) 哪里:

Keyword::getId是一個鍵映射器函數。

KeywordMerged.from(...)執行轉換: Keyword => KeywordMerged

(left, right) -> { .. }組合具有相同ID的實體的指標。

Collection<KeywordMerged> result = keywords.stream()
    .collect(Collectors.toMap(
        Keyword::getId,
        k -> KeywordMerged.from(k), // you can replace this lambda with a method reference
        (left, right) -> {
            left.getMetricList().addAll(right.getMetricList());
            return left;
        }))
    .values();

轉換方法可能看起來像這樣:

public class KeywordMerged {
    public static KeywordMerged from(Keyword k) {            
        KeywordMetric metric = new KeywordMetric();
        metric.setPrice(k.getPrice());
        metric.setMetricDay(k.getMetricDay());
        metric.setPosition(k.getPosition());

        KeywordMerged merged = new KeywordMerged();
        merged.setId(k.getId());
        merged.setName(k.getName());
        merged.setOwner(k.getOwner());
        merged.setMetricList(new ArrayList<>(Arrays.asList(metric)));
        return merged;
    }
}

我認為您已經有了基本的想法。 因此,請根據您的需求進行重構...

略有不同的方法。 首先,您收集按ID分組的關鍵字地圖:

Map<Integer, List<Keyword>> groupedData = keywords.stream()
    .collect(Collectors.groupingBy(k -> k.getId()));

進一步,您將地圖轉換為所需格式的列表:

List<KeywordMerged> finalData = groupedData.entrySet().stream()
    .map(k -> new KeywordMerged(k.getValue().get(0).getId(),
        k.getValue().stream()
            .map(v -> new KeywordMetric(v.getMetricDay(), v.getPrice(), getPosition()))
            .collect(Collectors.toList())))
    .collect(Collectors.toList());

這將對分組數據起作用,但是轉換地圖將創建KeywordMerged對象,該對象將作為參數接收ID(您可以自己進一步擴展),並轉換為先前按ID數據分組的List<KeywordMetric>

編輯:我相信與一些方法的提取,您可以使其看起來更好:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM