首页 > 解决方案 > 可以使用一些帮助优化此数据分组

问题描述

已经很长时间了,我正在尝试优化一些代码,所以我不必查看 4 个嵌套的 for 循环。我正在处理一组结构类似这样的数据

[
  [
    {
      Key1: Value1,
      ...
      Key2: [{
         ...
         Key3: {
            Key4: {
               Key5: Value2,
            },
            Key6: {
               Key7: Value3,
            },
            ...
         }
      }]
    }
    ...
  ]
]

为破旧的代表道歉。我无法分享数据的实际样本。我需要的是一个按多个字段分组的集合。目前,代码如下所示

foreach (var collection in response.Property1.Collections)
{
   var firstGroups = collection.GroupBy(items => items.Key1);

   foreach (var group in firstGroups)
   {
     var secondGroups = group.GroupBy(items => items.Key2.FirstOrDefault().Key3.Key4.Key5);
                    
     foreach(var secondGroup in secondGroups)
     {
        var thirdGroups= secondGroup.GroupBy(items =>  items.Key2.FirstOrDefault()?.Key3.Key6.Key7);

       foreach(var thirdGroup in thirdGroups)
       {
         yield return new ResultGroup
         {
           GroupKey= thirdGroup.Key,
           Collection = thirdGroup,
           ...
         };
       }
     }
   }
}

不幸的是,我被源数据困住了。我也没有奢侈地重新映射上游数据以允许在这里进行更好的转换。我真的不喜欢这些嵌套循环,并且对想法持开放态度!

标签: c#linq

解决方案


我的建议是将每个 foreach 放在一个单独的方法中,并让这些方法相互调用。如果您使用有意义的名称,这将不是问题。

优点:更容易理解每​​个过程会做什么,更容易对它们进行单元测试,更容易重用和维护。

您从一系列集合开始:

IEnumerable<Libraries> Libraries = ...

foreach (var library in libraries)
{
    IEnumerable<Book> books = GetBooks(library);
    foreach (var book in books) 
        yield return book;
}

IEnumerable<Book> GetBooks(Library library)
{
    // FirstGroup: make groups of departments in the Library:
    IEnumerable<int, Department> departmentGroups = library.GroupBy(...);
    IEnumerable<Book> books = GetBooks(departmentGroup)
    foreach (var book in books)
       yield return book;
}

IEnumerable<Book> GetBooks(IGrouping<int, Department> departmentGroups)
{
    // SecondGroup: group the bookcases in the departments by location code
    IEnumerable<...> bookCasesInSameLocation = departmentGroup.GroupBy(...);
    IEnumerable<Book> books = GetBooks(bookCasesInSameLocation)
    foreach (var book in books)
       yield return book;
}

依此类推,这也适用于 GroupBy 以外的其他 LINQ 语句

IEnumerable<Book> GetBooks(IEnumerable<...> bookCaseLocations)
{
    IEnumerable<...> bookShelves = bookCaseLocations.Where(...)
        .Where(...)
        .Select(...);
    IEnumerable<Book> books = GetBooks(bookShelves)
    foreach (var book in books)
       yield return book;
}

以此类推,直到最后一级:

IEnumerable<Book> GetBooks(BookShelve bookShelve)
{
     foreach (Book book in bookShelve.Books.Where(...).Select(...))
     {
         yield return book;
     }
}

挑战当然是为中间结果定义正确的名称和类。但是恕我直言,如果您找不到合适的名称,您确定您知道每个 GroupBy 和其他 LINQ 语句代表什么吗?


推荐阅读