Java Streams: Combining two collections into a map

Viewed 1012

I have two Collections, a list of warehouse ids and a collection of widgets. Widgets exist in multiple warehouses in varying quantities:

List<Long> warehouseIds;
List<Widget> widgets;

Here's an example defeinition of classes:

public class Widget {
    public Collection<Stock> getStocks();
}

public class Stock {
    public Long getWarehouseId();
    public Integer getQuantity();
}

I want to use the Streams API to create a Map, where the warehouse ID is the key, and the value is a list of Widgets with the smallest quantity at a particular warehouse. Because multiple widgets could have the same quantity, we return a list.

For example, Warehouse 111 has 5 qty of Widget A, 5 of Widget B, and 8 of Widget C.

Warehouse 222 has 0 qty of Widget A, 5 of Widget B, and 5 of Widget C The Map returned would have the following entries:

111 => ['WidgetA', 'WidgetB']

222 => ['WidgetA']

Starting the setup of the Map with keys seems pretty easy, but I don't know how to structure the downstream reduction:

warehouseIds.stream().collect(Collectors.groupingBy(
    Function::Identity,
    HashMap::new,
    ???...

I think the problem I'm having is reducing Widgets based on the stock warehouse Id, and not knowing how to return a Collector to create this list of Widgets. Here's how I would currently get the list of widgets with the smallest stock at a particular warehouse (represented by someWarehouseId):

widgets.stream().collect(Collectors.groupingBy(
    (Widget w)->
        w.getStocks()
        //for a specific warehouse
        .stream().filter(stock->stock.getWarehouseId()==someWarehouseId)
        //Get the quantity of stocks for a widget
        .collect(Collectors.summingInt(Stock::getQuantity)),
    //Use a tree map so the keys are sorted
    TreeMap::new,
    //Get the first entry
    Collectors.toList())).firstEntry().getValue();

Separating this into two tasks using forEach on the warehouse list would make this job easy, but I am wondering if I can do this in a 'one-liner'.

1 Answers
Related