Linq:按条件和 n 的最大大小拆分列表

Linq: Split list by condition and max size of n

我想转换一个数组:

["a", "b", "b", "a", "b", "a", "b"]

["a", "a", "b", "b", "a", "b", "b"]["b", "b", "a", "a", "b", "b", "a"]

我想按照特殊条件匹配的方式对数组进行分组。在我的情况下 item == 'a'item == 'b'。我想将这些组分成 2 组。我目前对如何以优雅的方式进行操作有点困惑。

有人能帮忙吗?

也许下面更清楚:

我喜欢将数组分组为 'a' 和 'b'-items 首先像这样:

一组:

["a","a","a"]

b组:

["b","b","b","b"]

然后我想将其分成 2 组:

一组:

["a","a"]
["a"]

b组:

["b","b"]
["b","b"]

现在我想将它们合并在一起得到结果:

["a","a","b","b","a","b","b"]

(每组总是 2 个合并在一起)

我认为为了简单起见,将数组转换为列表然后使用 findall() 将是最简单的方法。

List<char> list = new List<char>(['a', 'a', 'b'...]);

如果你使用谓词,那么你可以自动过滤一个列表来提取两个元素中的每一个,如下所示

a_elements = list.findall((char c) -> { return c == item; });

那么对于b你可以做

b_elements = list.findall((char c) -> { return c != item; });

其中 (char c) -> { return c... } 是一个谓词,一个方法 returns 当列表中的项目符合条件时为真,否则为假,您也可以使用微软的谓词 class 来形成这些,但我更喜欢 lambda 函数。

现在 a_elementsb_elements 是包含每个对应 findall() 调用的匹配项的数组

从那里你所要做的就是将数组分组为两个

首先你需要GroupBy你的数据。假设对象是 string 但无论如何它都是无关紧要的,如果您有除此之外的任何其他条件,您的分组条件将会改变。

要实现此功能,您需要 MoreLinq 或简单地包括执行 "group by 2 and 1 for left overs" 的 Batch 扩展。详情可见here

note that the Batch(2) can be changed to whatever you need. If you put Batch(5) and you have 7 elements it will make 2 groups, one with 5 elements and one of 2 elements

 // be my data, 4 x a, 3 x b, 1 x c, 2 x d, As a list for easier linQ
 var data = new[] { "a", "a", "c", "b", "a", "b", "b", "d", "d", "a" }.ToList();

 // group by our condition. Here it's the value so very simple
 var groupedData = data.GroupBy(o => o).ToList();

 // transform all groups into a custom List of List of List so they are grouped by 2 internally
 // each list level represent Grouping -> Groups of 2 (or 1) -> element
 var groupedDataBy2 = groupedData.Select(grp => grp.ToList().AsEnumerable().Batch(2).ToList()).ToList();

 // find the group with the maximum amount of groups or 2 (and 1)
 var maxCount = groupedDataBy2.Max(grp => grp.Count());

 // will contain our final objects listed
 var finalObjects = new List<string>();

 // loop on the count we figured out and try add each group one by one
 for (int i = 0; i < maxCount; i++)
 {
     // try each group
     foreach (var group in groupedDataBy2)
     {
         // add the correct index to our final list only if the current group has enough to fill
         if (i < group.Count)
         {
             // add the data to our final list
             finalObjects.AddRange(group[i]);
         }
     }
 }

 // result here is : a,a,c,b,b,d,d,a,a,b
 var results = string.Join(",", finalObjects);