【问题标题】:Linq: Split list by condition and max size of nLinq:按条件拆分列表和n的最大大小
【发布时间】:2019-07-21 13:01:48
【问题描述】:

我想转换一个数组:

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

【问题讨论】:

  • 不清楚你在问什么。
  • 你在第一个数组中犯了错误吗?你不是说["a", "a", "a", "b", "b"]
  • 如果不清楚我在问什么,我很抱歉。首先,我想将数组分成两组以仅获取“a”项和“b”项。然后我想将这两个组分成最大大小为 2。然后我想将每组“a”项与“b”项组合并。
  • @BlackMatrix 所以你想要一个组,然后是一个 bin(2)。
  • 现在清楚了吗?添加了一些附加信息。

标签: c# linq group-by chunks


【解决方案1】:

首先你需要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);

【讨论】:

  • 我想你会成为我的英雄 :) 我想试试你的代码,但似乎 Partition 方法需要一个 lambda 而不仅仅是一个 int。我错过了任何扩展吗?
  • @BlackMatrix。那么源代码调用其他方法。最简单的方法是确保将库添加到您的项目中。有 10 个过载。你可能只拿了其中一个。
  • 我安装了nuget包morelinq.3.1.0
  • @BlackMatrix 我正在检查,他们在某个时候删除了该过载。我正在寻找新的
  • 它可能是一个额外的扩展吗?我尝试使用了几个版本,但还没有找到。
【解决方案2】:

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

List&lt;char&gt; list = new List&lt;char&gt;(['a', 'a', 'b'...]);

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

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

那么对于 b 你可以这样做

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

(char c) -&gt; { return c... } 是谓词,当列表中的项目符合条件时,方法返回 true,否则返回 false,您也可以使用 Microsoft 的 Predicate 类来形成这些,但我更喜欢 lambda 函数。

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

你所要做的就是将数组分成两个一组

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    相关资源
    最近更新 更多