Home > Enterprise >  LINQ for checking whether all members of a list are contained within values from a Dictionary
LINQ for checking whether all members of a list are contained within values from a Dictionary

Time:03-15

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:

  1. intersect quantityByWarehouseByProductId (by the dictionary key) with productIds, to keep only the relevant entries in quantityByWarehouseByProductId
  2. select all the quantity by warehouse ID inner dictionary entries associated with each relevant product ID and flatten the collection of those, using SelectMany()
  3. group the result by the warehouse ID (which is the inner dictionary key)
  4. keep only the quantity by warehouse ID entries where all the desired products are in stock
  5. 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 ID
  • qbw: quantity by warehouse
  • qsbw: 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:

  1. 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)
  1. Transform to Warehouses List.
  2. Flatten the Warehouses List.
  3. .GroupBy WarehouseId.
  4. Transform grouped Warehouse data with IsAllProductsAvailable.
  5. 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();

Sample program

Output

[{
  "WarehouseId": 3,
  "IsAllProductsAvailable": true,
  "Products": [
    {"ProductId":12345,"WarehouseId":3,"Quantity":1}, 
    {"ProductId":23456,"WarehouseId":3,"Quantity":50}, 
    {"ProductId":34567,"WarehouseId":3,"Quantity":20}
  ]
}]
  • Related