从列表中选择值

时间:2014-08-12 14:30:33

标签: c# linq

我有以下列表:

public class Products
{
 public string SKU;
 public int WarehouseID;
}

List<Products> products = new List<Products>();

在填充列表后,我最终得到以下数据:

ProductCode|WarehouseID
SKU001|2
SKU001|3
SKU002|3
SKU003|3
SKU004|1
SKU004|5

我有多个SKU,因为该物品可以从库存中的多个仓库位置提供。对于SKU001,仓库ID 2的库存多于仓库ID 3。

我需要从最少数量的仓库位置中选择项目。我最终想要的是

SKU001|3
SKU002|3
SKU003|3
SKU004|1

这限制了产品选择仅限于2个位置,如SKU001,SKU002&amp; SKU003都可以从仓库ID 3中获取。理想情况下,选择库存最多但限制位置数量的位置更为重要。

我正在使用Linq尝试实现这一点,同时尝试循环每个List项目,但我正在努力,因为Linq对我来说不是一个强项。我试图首先使用

获得重复仓库ID的最高计数
products.GroupBy(i => i).OrderByDescending(grp => grp.Count()).Select(grp => grp.Key).FirstOrDefault();

但我对其余的项目感到迷茫。关于如何实现这一点的任何想法?

3 个答案:

答案 0 :(得分:1)

您可以在多个语句中执行此操作,首先获取WarehouseID以及每个仓库中的不同产品,并将其计数如下:

var query = products.GroupBy(r => r.WarehouseID)
                    .Select(grp => new
                    {

                        WarehouseID = grp.Key,
                        DistinctProducts = grp.Select(r => r.SKU).Distinct(),
                        DistinctCount = grp.Select(r => r.SKU).Distinct().Count(),
                    });

稍后创建一个结果列表,如:

List<Products> result = new List<Products>();

foreach (var item in query.OrderByDescending(r => r.DistinctCount)) //warehouse with most products
{
    if (!result.Any(r => item.DistinctProducts.Any(t => t == r.SKU)))
    {
        result.AddRange(item.DistinctProducts.Select(r => new Products { SKU = r, WarehouseID = item.WarehouseID }));
    }
}

输出:

foreach (var item in result)
{
    Console.WriteLine("{0} | {1}", item.SKU, item.WarehouseID);
}

输出:

SKU001 | 3
SKU002 | 3
SKU003 | 3
SKU004 | 1

答案 1 :(得分:0)

修改 我已根据每个仓库中库存的产品数量更新了我的查询,而不是每个产品的库存。

var productQ2 = products.GroupBy(product => product.WarehouseId)
                        .SelectMany(wGroup => wGroup.Select(product => new
                                                                        {
                                                                            Product = product,
                                                                            WarehouseProductCount = wGroup.Select(p => p.SKU)
                                                                                                          .Distinct()
                                                                                                          .Count()
                                                                        }))
                        .GroupBy(product => product.Product.SKU)
                        .Select(pGroup => pGroup.OrderByDescending(product => product.WarehouseProductCount).First().Product);

原始回答:

无法访问每个仓库中的库存量,因此您需要将其添加到模型中。

public class Product
{
 public string SKU;
 public int WarehouseID;
 public int StockCount;
}

List<Product> products = new List<Product>();

然后获取您的查询结果:

products.GroupBy(product => product.SKU)
        .Select(group => group.OrderByDescending(product => product.StockCount).First())

答案 2 :(得分:0)

这是一个产生最小仓库ID的解决方案:

// Number of product SKUs
int nProducts = products.Select(p => p.SKU).Distinct().Count();
// Warehouses and their products
Dictionary<int, List<Product>> warehouses = products
    .GroupBy(p => p.WarehouseID)
    .ToDictionary(g => g.Key, g => g.ToList());
List<int> minWarehouseSet = warehouses
    // Get list of unique warehouse ids
    .Select(p => p.Key).ToList()
    // Get all combinations of warehouses
    .Combinations()
    // Order sets by the number of items
    .OrderBy(ws => ws.Count())
    // Find set which satisfies requirement (contains all products)
    .First(ws => ws.SelectMany(w => warehouses[w]).Distinct().Count() == nProducts)
    .ToList();
foreach (var product in products.Where(p => minWarehouseSet.Contains(p.WarehouseID)))
    Console.WriteLine("{0}|{1}", product.SKU, product.WarehouseID);

它需要以下扩展方法:

public static IEnumerable<IEnumerable<T>> Combinations<T>(this IList<T> allValues)
{
    for (int counter = 0; counter < (1 << allValues.Count); ++counter)
        yield return allValues.Where((_, i) => (counter & 1 << i) == 0).ToList();
}

输出:

SKU001|3
SKU002|3
SKU003|3
SKU004|5

注意:

  1. 此解决方案对最佳仓库集执行强力搜索。可能有更好的解决方案。
  2. 仓库数量仅限于int方法{(1}}中的位数(即32)。您可以选择其他变量类型或以不同方式实现该方法。
  3. 您提供的数据不包含库存,但您尚未指定它对结果的影响。如果您需要考虑库存,请调整订购(测量&#34;质量&#34;结果)或过滤(严格条件)。