2016-03-19 7 views
6

Sono abbastanza sicuro che questo non è possibile in una sola riga, ma ho solo voluto verificare:Java Streams: organizzare una raccolta in una mappa e selezionare la più piccola chiave

List<WidgetItem> selectedItems = null; 
Map<Integer, List<WidgetItem>> itemsByStockAvailable = WidgetItems.stream() 
    .collect(Collectors.groupingBy(WidgetItem::getAvailableStock)); 
selectedItems = itemsByStockAvailable.get(
    itemsByStockAvailable.keySet().stream().sorted().findFirst().get()); 

Fondamentalmente sto raccogliendo tutti i widget di elementi in una mappa in cui la chiave è la quantità di StockStock e il valore è un elenco di tutti i widget che hanno quella quantità (poiché più widget potrebbero avere lo stesso valore). Una volta che ho quella mappa, vorrei selezionare il valore della mappa che corrisponde alla chiave più piccola. Il passaggio intermedio della creazione di una mappa non è necessario, è solo l'unico modo in cui potrei pensare di farlo.

risposta

6

Appare ciò che si desidera mantenere tutti gli elementi del widget raggruppati con lo stock disponibile più basso. In tal caso, è possibile raccogliere i dati raggruppati in un TreeMap per garantire l'ordinamento in base ai valori dello stock crescente e recuperare la prima voce con firstEntry()

List<WidgetItem> selectedItems = 
    widgetItems.stream() 
       .collect(Collectors.groupingBy(
        WidgetItem::getAvailableStock, 
        TreeMap::new, 
        Collectors.toList() 
       )) 
       .firstEntry() 
       .getValue(); 

Il vantaggio è che si è fatto è uno-passare sopra la lista iniziale

+0

Ah- TreeMap. Mi sono dimenticato di quella classe visto che è passato un po 'di tempo da quando dovevo usarla. Grazie! – IcedDante

+3

Se si preferisce racchiudere tutto in un unico flusso, si potrebbe anche fare 'Collectors.collectingAndThen (Collectors.groupingBy (...), x -> x.firstEntry(). GetValue())' – user140547

1

È possibile trovare la chiave più piccola in un primo passaggio e quindi ottenere tutte le voci avere quella chiave più piccola:

widgetItems.stream() 
      .map(WidgetItem::getAvailableStock) 
      .min(Comparator.naturalOrder()) 
      .map(min -> 
       widgetItems.stream() 
          .filter(item -> item.getAvailableStock().equals(min)) 
          .collect(toList())) 
      .orElse(Collections.emptyList()); 
1

Se si vuole evitare di creare la mappa intermedio, è possibile innanzitutto determinare il valore più piccolo magazzino , filtra per quel valore e raccogli per elencare.

int minStock = widgetItems.stream() 
    .mapToInt(WidgetItem::getAvailableStock) 
    .min() 
    .getAsInt(); // or throw if list is empty 

List<WidgetItem> selectItems = widgetItems.stream() 
    .filter(w -> minStock == w.getAvailableStock()) 
    .collect(toList()); 

Inoltre, non utilizzare sorted().findFirst() per trovare il valore minimo di un torrente. Utilizzare invece min.

0

vorrei raccogliere i dati in un NavigableMap, che coinvolge solo una piccola modifica al codice originale:

List<WidgetItem> selectedItems = null; 
NavigableMap<Integer, List<WidgetItem>> itemsByStockAvailable = 
    WidgetItems.stream() 
     .collect(Collectors.groupingBy(WidgetItem::getAvailableStock, 
      TreeMap::new, Collectors.toList())); 
selectedItems = itemsByStockAvailable.firstEntry().getValue(); 
2

In sostanza si desidera ottenere tutti gli elementi di input che sono il minimo in base al confronto personalizzato Comparator.comparingInt(WidgetItem::getAvailableStock). In generale questo problema può essere risolto senza necessità per memorizzare tutto nella mappa intermedia creando inutili inutili rifiuti. Inoltre potrebbe essere risolto in single pass. Alcune soluzioni interessanti già presenti nella domanda this. Ad esempio, è possibile utilizzare il collettore realizzato da Stuart Marks:

List<WidgetItem> selectedItems = widgetItems.stream() 
      .collect(maxList(
       Comparator.comparingInt(WidgetItem::getAvailableStock).reversed())); 

Tali collettori sono facilmente disponibili nella mia biblioteca StreamEx. Il migliore adatto nel tuo caso è MoreCollectors.minAll(Comparator):

List<WidgetItem> selectedItems = widgetItems.stream() 
      .collect(MoreCollectors.minAll(
       Comparator.comparingInt(WidgetItem::getAvailableStock))); 
Problemi correlati