簡體   English   中英

Java 流:groupingBy 和 flatMapping 鍵

[英]Java streams: groupingBy and flatMapping keys

假設我有一個國家對象列表,其中包含該國家/地區使用的語言列表,如下所示:

class Country {
    List<String> languages; 
}

我想以以下格式創建地圖: Map<String, List<Country>> ,這樣每種語言都映射到 Country 對象列表。 例如:

"French" -> [Country:France, Country:Canada],
"English" -> [Country:UK, Country:US]

性能在這里是一個問題,所以我想避免多次迭代和查找。 我曾嘗試使用groupingBy ,但如何flatMap鍵集?

例如,這導致Map<List<String>, List<Country>>

countries.stream()
    .collect(Collectors.groupingBy(country -> country.getLanguages(), toList()));

由於您似乎關心性能,因此不要將流用於這個簡單的任務:

Map<String, List<Country>> countriesByLanguage = new HashMap<>();
for (Country country : countries) {
    for (String language : country.getLanguages()) {
        countriesByLanguage.computeIfAbsent(language, k -> new ArrayList<>())
                           .add(country);
    }
}

您可以使用流中的流來完成,如下所示:首先迭代國家列表,然后迭代嵌套的語言列表並准備«language, country»對,然后收集它們以進行映射:

public static void main(String[] args) {
    List<Country> countries = List.of(
            new Country("France", List.of("French")),
            new Country("Canada", List.of("French")),
            new Country("UK", List.of("English")),
            new Country("US", List.of("English")));

    Map<String, List<Country>> map = countries.stream()
            // Stream<Map.Entry<String,Country>>
            .flatMap(country -> country.getLanguages().stream()
                    .map(lang -> Map.entry(lang, country)))
            .collect(Collectors.toMap(
                    // key - language
                    Map.Entry::getKey,
                    // value - List<Country>
                    entry -> new ArrayList<>(List.of(entry.getValue())),
                    // merge duplicates, if any
                    (list1, list2) -> {
                        list1.addAll(list2);
                        return list1;
                    }
            ));

    // output
    map.forEach((k, v) -> System.out.println(k + "=" + v));
    //English=[Country:UK, Country:US]
    //French=[Country:France, Country:Canada]
}
static class Country {
    String name;
    List<String> languages;

    public Country(String name, List<String> languages) {
        this.name = name;
        this.languages = languages;
    }

    public List<String> getLanguages() {
        return languages;
    }

    @Override
    public String toString() {
        return "Country:" + name;
    }
}

這樣做:

countries.stream()
        .flatMap(country -> country.getLanguages()
                .stream()
                .map(lang -> new SimpleEntry<>(lang,
                        new ArrayList<>(Arrays.asList(country)))))
        .collect(Collectors.toMap(
                Entry::getKey,
                Entry::getValue,
                (l1, l2) -> {
                    l1.addAll(l2);
                    return l2;
                }));

暫無
暫無

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

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