2015-08-06 7 views
5

Ho un oggetto:Java 8 Raccogliere due liste a Map per condizione

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

dove CurrencyName è uno dei: EUR, USD, ecc RUR

E due liste

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

Come unire questi elenchi allo Map<CurrencyItem, CurrencyItem> dove le chiavi sono currenciesByCommercialBank e i valori sono currenciesByCentralBank con condizioni come

currenciesByCommercialBank.CurrencyName == currenciesByCentralBank.CurrencyName 

risposta

5

Questo dovrebbe essere ottimale. Per prima cosa costruisci una mappa dalle valute alle loro banche commerciali. Quindi attraversi le tue centrali creando una mappa da commerciale a centrale (cercata nella prima mappa).

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

Il seguente codice è O (n), ma dovrebbe essere OK per piccole collezioni (che le vostre liste, probabilmente sono):

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

Quanto sopra è appropriata se si vuole far valere che currenciesByCentralBank contenga una corrispondenza per ogni articolo in currenciesByCommercialBank. Se le due liste possono avere disallineamenti, allora quanto segue sarebbe opportuno:

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 questo caso la carta conterrà tutte le partite e non si lamenta perché le voci mancanti.