如何使用LINQ在集合中查找重叠(不是重复,而是查找重叠)

时间:2018-08-13 15:27:30

标签: c# linq iequalitycomparer

List<StoreDetailDto> items = new List<StoreDetailDto>();

items.Add(new StoreDetailDto { StoreNumber = 2, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 3, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 6, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 7, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 9, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});

items.Add(new StoreDetailDto { StoreNumber = 6, WarehouseNumber = 4202, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 7, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 9, WarehouseNumber = 4203, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});
items.Add(new StoreDetailDto { StoreNumber = 9, WarehouseNumber = 4207, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1"});

我上面有一个集合,其中商店6、9之间有重叠,但商店7没有重叠,这是重复项。我发现同一家商店有不同仓库的重叠。

为了确保我正在执行以下操作:

var overlapDupStores = items.GroupBy(
    u => u.StoreNumber,
    u => { return u; },
    (key, g) => g.ToList())
  .ToList()
  .Where(cnt => cnt.Count() > 1);


foreach (var dpovl in overlapDupStores)
{
    var stores = dpovl.Where(g => g.IsResolved != true).GroupBy(u => new { u.StoreNumber, u.WarehouseNumber }).ToList();

    if (stores.Count() > 1)
    {
        response.OverlappingStores.AddRange(stores.SelectMany(gr => gr).ToList());
    }
}

我首先找到重复的商店,它将在对象内部具有重复数为2的商店重复对象,然后按商店编号和仓库编号分组,不同商店和仓库的数量仍为2,但对于相同商店和仓库这是重复项,它将是count = 1,所以我发现count> 1,这样我就可以找到重复项,并检查Isresolved是否在解决后不再再次拉相同的存储。

下面是小提琴:

https://dotnetfiddle.net/TknnkJ

3 个答案:

答案 0 :(得分:4)

使用LINQ的GroupBy().Select().Where()尝试此操作,根据显示的输出,根据我假设的条件对对象列表进行分组和过滤。

说明:

  

GroupBy() =>使用StoreNumber对对象进行分组   属性。
  Select() =>选择对象   IsResolved属性是false
  Where() =>过滤   具有1个以上具有不同元素的对象   WarehouseNumber
  SelectMany()=>使分组变平,   顺序视图中的所有匹配对象

如果需要,可以添加

OrderBy()以在StoreNumber ThenBy() WarehouseNumber上订购列表。

Duplicates过滤器可能不正确,具体取决于使用情况。可能需要对其进行调整。

var Duplicates = 
    items.GroupBy(store => store.StoreNumber)
         .Select(grp => grp.Where(store => store.IsResolved == false))
         .Where(stores => stores.Count() > 1 && stores.Select(w => w.WarehouseNumber).Distinct().Count() == 1)
         .SelectMany(stores => stores)
         .ToList();

var Overlapping = 
    items.GroupBy(store => store.StoreNumber)
         .Select(grp => grp.Where(store => store.IsResolved == false))
         .Where(store => store.Count() > 1 && store.Select(w => w.WarehouseNumber).Distinct().Count() > 1)
         .SelectMany(stores => stores)
         .ToList();

Overlapping.ForEach(ovr =>
    Console.WriteLine($"{ovr.StoreNumber} " +
                      $"{ovr.WarehouseNumber} " +
                      $"{ovr.IsResolved} " +
                      $"{ovr.StoreName} " +
                      $"{ovr.WarehouseName}"));

Overlapping列表打印:

6 4201 False StoreEx WarehouseEx1
6 4202 False StoreEx WarehouseEx1
9 4201 False StoreEx WarehouseEx1
9 4203 False StoreEx WarehouseEx1
9 4207 False StoreEx WarehouseEx1

Duplicates列表打印:

7 4201 False StoreEx WarehouseEx1
7 4201 False StoreEx WarehouseEx1

答案 1 :(得分:1)

我认为这些查询可以完成工作:

var overlaps =
    items
        .GroupBy(x => new { x.StoreNumber, x.WarehouseNumber })
        .GroupBy(x => x.Key.StoreNumber)
        .Where(x => x.Skip(1).Any())
        .Where(x => !x.Any(y => y.Any(z => z.IsResolved)))
        .SelectMany(x => x.SelectMany(y => y))
        .ToList();

overlaps

var duplicates =
    items
        .GroupBy(x => new { x.StoreNumber, x.WarehouseNumber })
        .GroupBy(x => x.Key.StoreNumber)
        .Where(x => !x.Skip(1).Any())
        .Where(x => x.First().Skip(1).Any())
        .Where(x => !x.Any(y => y.Any(z => z.IsResolved)))
        .SelectMany(x => x.SelectMany(y => y))
        .ToList();  

duplicates

我使用了此源数据:

var items = new List<StoreDetailDto>()
{
    new StoreDetailDto { StoreNumber = 2, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 3, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 6, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 7, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 9, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 6, WarehouseNumber = 4202, IsResolved = true, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 7, WarehouseNumber = 4201, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 9, WarehouseNumber = 4203, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
    new StoreDetailDto { StoreNumber = 9, WarehouseNumber = 4207, IsResolved = false, StoreName = "StoreEx", WarehouseName = "WarehouseEx1" },
};

值得注意的是,如果7要拥有新的WarehouseNumber的第三条记录,它将出现在overlaps结果中,并将在其中包含重复项。

答案 2 :(得分:0)

如果我对您的理解正确。以下内容将为您提供所需的信息。

   var warehouseCountsByStore =
            from item in items
            group item by new { item.StoreNumber, item.WarehouseNumber } into store
            where store.Count() != 0
            select new
            {
                store.Key.StoreNumber,
                store.Key.WarehouseNumber,
                Count = store.Count()
            };

    var storesWithDuplicateWarehouses =
        from warehouse in warehouseCountsByStore
        where warehouse.Count != 1
        select new { warehouse.StoreNumber };

    var storesWithMultipleWarehouse =
        from item in items
        group item by new { item.StoreNumber } into store
        where store.Count() > 1
              && storesWithDuplicateWarehouses.Any(x => x.StoreNumber != store.Key.StoreNumber)
        select new
        {
            store.Key.StoreNumber
        };

    Console.WriteLine("Duplicates");
    foreach (var store in storesWithDuplicateWarehouses)
        Console.WriteLine(store.StoreNumber);

    Console.WriteLine("Overlap");
    foreach (var store in storesWithMultipleWarehouse)
        Console.WriteLine(store.StoreNumber);