简体   繁体   中英

Java 8 Collect two Lists to Map by condition

I have an object:

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

where CurrencyName is one of: EUR, USD, RUR etc.

And two lists

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

How can I merge this lists to the Map<CurrencyItem, CurrencyItem> where keys are currenciesByCommercialBank and values are currenciesByCentralBank with condition such as

currenciesByCommercialBank.CurrencyName == currenciesByCentralBank.CurrencyName

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
                    ));

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

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 currenciesByCentralBank contains a match for each item in currenciesByCommercialBank . If the two lists can have mismatches, then the following would be appropriate:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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