Java 8 收集两个列表以按条件映射

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31855403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 19:15:30  来源:igfitidea点击:

Java 8 Collect two Lists to Map by condition

javacollectionsjava-8java-stream

提问by marknorkin

I have an object:

我有一个对象:

public class CurrencyItem {
    private CurrencyName name;
    private BigDecimal buy;
    private BigDecimal sale;
    private Date date;
    //...
}

where CurrencyNameis one of: EUR, USD, RUR etc.

其中CurrencyName之一是:EUR、USD、RUR 等。

And two lists

和两个清单

List<CurrencyItem> currenciesByCommercialBank = ...
List<CurrencyItem> currenciesByCentralBank = ...

How can I merge this lists to the Map<CurrencyItem, CurrencyItem>where keys are currenciesByCommercialBankand values are currenciesByCentralBankwith condition such as

如何将此列表合并到Map<CurrencyItem, CurrencyItem>键所在位置currenciesByCommercialBank和值所在currenciesByCentralBank的条件,例如

currenciesByCommercialBank.CurrencyName == currenciesByCentralBank.CurrencyName

采纳答案by OldCurmudgeon

This should be optimal. You first build a map from the currencies to their commercial banks. Then you run through your centrals building a map from commercial to central (looked up in the first map).

这应该是最佳的。您首先构建一张从货币到其商业银行的地图。然后你运行你的中心构建一张从商业到中心的地图(在第一张地图中查找)。

    List<CurrencyItem> currenciesByCommercialBank = new ArrayList<>();
    List<CurrencyItem> currenciesByCentralBank = new ArrayList<>();
    // Build my lookup from CurrencyName to CommercialBank.
    Map<CurrencyName, CurrencyItem> commercials = currenciesByCommercialBank
            .stream()
            .collect(
                    Collectors.toMap(
                            // Map from currency name.
                            ci -> ci.getName(),
                            // To the commercial bank itself.
                            ci -> ci));
    Map<CurrencyItem, CurrencyItem> commercialToCentral = currenciesByCentralBank
            .stream()
            .collect(
                    Collectors.toMap(
                            // Map from the equivalent commercial
                            ci -> commercials.get(ci.getName()),
                            // To this central.
                            ci -> ci
                    ));

回答by Marko Topolnik

The following code is O(n2), but it should be OK for small collections (which your lists probably are):

以下代码是 O(n 2),但对于小型集合(您的列表可能是)应该没问题:

return currenciesByCommercialBank
    .stream()
    .map(c ->
        new AbstractMap.SimpleImmutableEntry<>(
            c, currenciesByCentralBank.stream()
                                      .filter(c2 -> c.currencyName == c2.currencyName)
                                      .findFirst()
                                      .get()))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  }

The above is appropriate if you want to assert that currenciesByCentralBankcontains a match for each item in currenciesByCommercialBank. If the two lists can have mismatches, then the following would be appropriate:

如果您想断言currenciesByCentralBank包含currenciesByCommercialBank. 如果这两个列表可能不匹配,那么以下是合适的:

currenciesByCommercialBank
    .stream()
    .flatMap(c ->
        currenciesByCentralBank.stream()
                               .filter(c2 -> c.currencyName == c2.currencyName)
                               .map(c2 -> new AbstractMap.SimpleImmutableEntry<>(c, c2)))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

In this case the map will contain all the matches and won't complain about missing entries.

在这种情况下,地图将包含所有匹配项,并且不会抱怨缺少条目。