在 Linq (C#) 中动态交叉连接多个不同大小的集合 [英] Dynamically cross-join multiple different-size collections together in Linq (C#)
问题描述
我有未知数量的桶(集合),每个桶都有未知数量的实体
I have an unknown number of buckets(collections), and each bucket having an unknown number of entities
我需要生成所有实体的笛卡尔积,以便我最终得到一个包含实体数组的集合,并且在每个数组中,每个存储桶都有 1 个代表.
I need to produce a cartesian product of all the entities, so that I endup with a single COLLECTION that has ARRAYS of entities and in each array, there is 1 representetive from EVERY bucket.
因此,如果我有 5 个桶 (B1..B5),并且桶 B1、B2 各有 1 个项目,而桶 B3、B4 和 B5 各有 4、8 和 10 个项目,我将收集320个数组,每个数组有5个元素.
So that if I have 5 buckets (B1..B5), and buckets B1, B2 have 1 item each, and bucket B3, B4 and B5 have 4, 8 and 10 items each, I'll have a collection of 320 arrays, and each array will have 5 items.
这里唯一愚蠢的问题是,在开发时,桶的大小和桶的数量都是未知的.
The only stupud issue here, is that both size of buckets and number of buckets is unknown at development time.
性能在这里并不是特别重要,因为大多数时候,我的桶只有 1 个实体,而且很少有我的一些桶会包含 20-30 个项目的情况......我通常会有 5-30 个桶
Performance is not super important here, as most of the time, my buckets will have only 1 entity, and only rarely will there be times when some of my buckets will contain 20-30 items...and I'll usually have 5-30 buckets
我很想以某种方式在这里使用 linq,但是当我试图想象这将如何工作时,我的大脑正在被炸毁
I'd love to utilize linq here in someway, but my brain is getting fried as I try to imagine how this would work
推荐答案
您可以创建如下扩展方法:
You could create an extension method like the following:
public static class EnumerableExtensions
{
public static IEnumerable<TValue []> Permutations<TKey, TValue>(this IEnumerable<TKey> keys, Func<TKey, IEnumerable<TValue>> selector)
{
var keyArray = keys.ToArray();
if (keyArray.Length < 1)
yield break;
TValue [] values = new TValue[keyArray.Length];
foreach (var array in Permutations(keyArray, 0, selector, values))
yield return array;
}
static IEnumerable<TValue []> Permutations<TKey, TValue>(TKey [] keys, int index, Func<TKey, IEnumerable<TValue>> selector, TValue [] values)
{
Debug.Assert(keys.Length == values.Length);
var key = keys[index];
foreach (var value in selector(key))
{
values[index] = value;
if (index < keys.Length - 1)
{
foreach (var array in Permutations(keys, index+1, selector, values))
yield return array;
}
else
{
yield return values.ToArray(); // Clone the array;
}
}
}
}
举个例子,它可以像这样使用:
As an example, it could be used like:
public static void TestPermutations()
{
int [][] seqence = new int [][]
{
new int [] {1, 2, 3},
new int [] {101},
new int [] {201},
new int [] {301, 302, 303},
};
foreach (var array in seqence.Permutations(a => a))
{
Debug.WriteLine(array.Aggregate(new StringBuilder(), (sb, i) => { if (sb.Length > 0) sb.Append(","); sb.Append(i); return sb; }));
}
}
并产生以下输出:
1,101,201,301
1,101,201,302
1,101,201,303
2,101,201,301
2,101,201,302
2,101,201,303
3,101,201,301
3,101,201,302
3,101,201,303
这就是你想要的吗?
这篇关于在 Linq (C#) 中动态交叉连接多个不同大小的集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!