Let's say I have a list of ProductId
:
12345
23456
34567
And a list of available quantities of each product in various warehouses, by id:
Dictionary<ProductId,Dictionary<WarehouseId,quantity>>
How could I check which warehouses have stock (quantity >= 1 of each) of all the products in the list? Is it possible to do it using LINQ?
CodePudding user response:
Let's say you have the following fields:
List<int> productIds;
Dictionary<int, Dictionary<int, int>> quantityByWarehouseByProductId;
You could then:
- intersect
quantityByWarehouseByProductId
(by the dictionary key) withproductIds
, to keep only the relevant entries inquantityByWarehouseByProductId
- select all the quantity by warehouse ID inner dictionary entries associated with each relevant product ID and flatten the collection of those, using
SelectMany()
- group the result by the warehouse ID (which is the inner dictionary key)
- keep only the quantity by warehouse ID entries where all the desired products are in stock
- select the warehouse ID
as follows:
IEnumerable<int> warehouseIdsWithAllProductsInStock = quantityByWarehouseByProductId
.IntersectBy(productIds, qbwForPid => qbwForPid.Key)
.SelectMany(qbwForPid => qbwForPid.Value)
.GroupBy(qbw => qbw.Key)
.Where(qsbw => qsbw.All(qbw => qbw.Value >= 1))
.Select(qsbw => qsbw.Key);
Trying to keep the names somewhat short, I have used the following abbreviations in the example:
qbwForPid
: quantity by warehouse for product IDqbw
: quantity by warehouseqsbw
: quantities by warehouse
Note: This approach assumes that all existing warehouse IDs are present in a KeyValuePair
in the inner dictionaries.
Example fiddle here.
CodePudding user response:
- Join
productIds
list
.Join(productIds,
x => x.Key,
y => y,
(x, y) => x)
or check productDict
contains key in productIds
.Where(x => productIds.Contains(x.Key)
- Transform to Warehouses List.
- Flatten the Warehouses List.
.GroupBy
WarehouseId.- Transform grouped Warehouse data with
IsAllProductsAvailable
. - Query warehouse(s) with
IsAllProductsAvailable = true
.
var result = productDict
.Join(productIds,
x => x.Key,
y => y,
(x, y) => x)
.Select(x => new
{
Warehouses = x.Value
.Select(y => new
{
ProductId = x.Key,
WarehouseId = y.Key,
Quantity = y.Value
})
.ToList()
})
.SelectMany(x => x.Warehouses)
.GroupBy(x => x.WarehouseId)
.Select(g => new
{
WarehouseId = g.Key,
IsAllProductsAvailable = g.All(x => x.Quantity >= 1),
Products = g.ToList()
})
.Where(x => x.IsAllProductsAvailable)
.ToList();
Output
[{
"WarehouseId": 3,
"IsAllProductsAvailable": true,
"Products": [
{"ProductId":12345,"WarehouseId":3,"Quantity":1},
{"ProductId":23456,"WarehouseId":3,"Quantity":50},
{"ProductId":34567,"WarehouseId":3,"Quantity":20}
]
}]