问题 如何使用LINQ在列表中生成重复项?


这是我用过的LINQ查询

var result = (from price in inventoryDb.Pricing.AsNoTracking()               
              where price.Quantity > 0m
              select new
              {
                 TagNo = price.TagNo,
                 SellingRate = price.SellingRate,
                 Quantity = price.Quantity           
              }).ToList();

基于 Quantity 值我需要在列表中生成重复的项目。

输出: 

result = [0]{TagNo="100", SellingRate=1500.00, Quantity=1}
         [1]{TagNo="101", SellingRate=1600.00, Quantity=2}

预期结果:

result = [0]{TagNo="100", SellingRate=1500.00}
         [1]{TagNo="101", SellingRate=1600.00}
         [2]{TagNo="101", SellingRate=1600.00}

2982
2017-10-07 09:47


起源



答案:


您可以使用 Enumerable.SelectMany + Enumerable.Range

var result = inventoryDb.Pricing.AsNoTracking()
    .Where(p => p.Quantity > 0m)
    .SelectMany(p => Enumerable.Range(0, p.Quantity)
        .Select(i => new
              {
                 TagNo = p.TagNo,
                 SellingRate = p.SellingRate      
              }))
    .ToList();

如果您的LINQ提供程序不支持(f.e。 Linq-To-Entities),最简单的就是使用 Linq-To-Objects。为了避免将所有内容加载到内存中,您应该使用 AsEnumerable 之后 Where

var result = inventoryDb.Pricing.AsNoTracking()
    .Where(p => p.Quantity > 0m)
    .AsEnumerable()
    .SelectMany(p => Enumerable.Range(0, p.Quantity)
        .Select(i => new
              {
                 TagNo = p.TagNo,
                 SellingRate = p.SellingRate      
              }))
    .ToList();

8
2017-10-07 09:52





保持查询语法只需添加一个 Enumerable.Repeat 如下:

var result = (from price in inventoryDb.Pricing.AsNoTracking()
              where price.Quantity > 0m
              from dup in Enumerable.Repeat(0,price.Quantity)
              select new
              {
                 TagNo = price.TagNo,
                 SellingRate = price.SellingRate,          
              }).ToList();

如果确实linq to entity不支持那么添加 AsEnumerable 如下:

var result = (from price in inventoryDb.Pricing.AsNoTracking()
                                               .Where(p => p.Quantity > 0m)
                                               .AsEnumerable() //Loads only the filtered items to memory            
              from dup in Enumerable.Repeat(0,price.Quantity)
              select new
              {
                 TagNo = price.TagNo,
                 SellingRate = price.SellingRate,          
              }).ToList();

你也可以使用 Enumerable.Range 但是因为你没有使用那个集合的价值(在我看来也只是它更好地描述了你在做什么)我决定只是去 Repeat


4
2017-10-07 09:53



这是明显的LINQ To Objects解决方案。问题是,这对EF有效吗(通知 inventoryDb.Pricing.AsNoTracking())。我会打赌 NotSupportedException :) - Ivan Stoev
@IvanStoev,请加上 .AsEnumerable() 在打电话之前 Enumerable.Repeat。 - kiziu
@IvanStoev - 感谢您的注意:)你是对的,我忘了查一下。见更新 - Gilad Green
@kiziu嗯,这就是重点 - 有人必须这样做:) - Ivan Stoev
@kiziu - 感谢您的建议 - Gilad Green


答案:


您可以使用 Enumerable.SelectMany + Enumerable.Range

var result = inventoryDb.Pricing.AsNoTracking()
    .Where(p => p.Quantity > 0m)
    .SelectMany(p => Enumerable.Range(0, p.Quantity)
        .Select(i => new
              {
                 TagNo = p.TagNo,
                 SellingRate = p.SellingRate      
              }))
    .ToList();

如果您的LINQ提供程序不支持(f.e。 Linq-To-Entities),最简单的就是使用 Linq-To-Objects。为了避免将所有内容加载到内存中,您应该使用 AsEnumerable 之后 Where

var result = inventoryDb.Pricing.AsNoTracking()
    .Where(p => p.Quantity > 0m)
    .AsEnumerable()
    .SelectMany(p => Enumerable.Range(0, p.Quantity)
        .Select(i => new
              {
                 TagNo = p.TagNo,
                 SellingRate = p.SellingRate      
              }))
    .ToList();

8
2017-10-07 09:52





保持查询语法只需添加一个 Enumerable.Repeat 如下:

var result = (from price in inventoryDb.Pricing.AsNoTracking()
              where price.Quantity > 0m
              from dup in Enumerable.Repeat(0,price.Quantity)
              select new
              {
                 TagNo = price.TagNo,
                 SellingRate = price.SellingRate,          
              }).ToList();

如果确实linq to entity不支持那么添加 AsEnumerable 如下:

var result = (from price in inventoryDb.Pricing.AsNoTracking()
                                               .Where(p => p.Quantity > 0m)
                                               .AsEnumerable() //Loads only the filtered items to memory            
              from dup in Enumerable.Repeat(0,price.Quantity)
              select new
              {
                 TagNo = price.TagNo,
                 SellingRate = price.SellingRate,          
              }).ToList();

你也可以使用 Enumerable.Range 但是因为你没有使用那个集合的价值(在我看来也只是它更好地描述了你在做什么)我决定只是去 Repeat


4
2017-10-07 09:53



这是明显的LINQ To Objects解决方案。问题是,这对EF有效吗(通知 inventoryDb.Pricing.AsNoTracking())。我会打赌 NotSupportedException :) - Ivan Stoev
@IvanStoev,请加上 .AsEnumerable() 在打电话之前 Enumerable.Repeat。 - kiziu
@IvanStoev - 感谢您的注意:)你是对的,我忘了查一下。见更新 - Gilad Green
@kiziu嗯,这就是重点 - 有人必须这样做:) - Ivan Stoev
@kiziu - 感谢您的建议 - Gilad Green