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

时间:2019-02-27 17:56:38

标签: c# linq group-by chunks

我要转换数组:

["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”项:

一个小组:

["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个合并在一起)

2 个答案:

答案 0 :(得分:2)

首先,您需要GroupBy数据。假设对象是string,但无论如何,只要没有其他条件,分组条件就会改变。

要执行此操作,您将需要MoreLinq或简单地包含Batch扩展名,该扩展名将“剩余的2和1分组”。可以找到详细信息here

  

请注意,Batch(2)可以更改为您需要的任何值。如果您将Batch(5)和   您有7个元素,它将组成2个组,一个包含5个元素,另一个包含2个元素

 // 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);

答案 1 :(得分:0)

为简单起见,我认为将数组转换为列表然后使用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... }是谓词,当列表中的某个项目符合条件时,方法将返回true,否则返回false,您也可以使用Microsoft的Predicate类来形成这些谓词,但是我更喜欢lambda函数。

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

从那里开始,您要做的就是将数组分成两个组