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_elements
和 b_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);
我想转换一个数组:
["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_elements
和 b_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 putBatch(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);