c# - 在 Linq (C#) 中动态交叉连接多个不同大小的集合

标签 c# linq cartesian-product

我有未知数量的桶(集合),每个桶有未知数量的实体

我需要生成所有实体的笛卡尔积,以便我最终得到一个包含实体数组的集合,并且在每个数组中,每个桶都有 1 个代表。

因此,如果我有 5 个桶 (B1..B5),桶 B1、B2 各有 1 个项目,桶 B3、B4 和 B5 各有 4、8 和 10 个项目,我将有一个集合320个数组,每个数组有5项。

这里唯一愚蠢的问题是,桶的大小和桶的数量在开发时都是未知的。

这里的性能并不是特别重要,因为大多数时候,我的存储桶只有 1 个实体,很少有一些存储桶包含 20-30 个项目......我通常会有5-30个桶

我很想在这里以某种方式利用 linq,但是当我试图想象这将如何工作时,我的大脑变得焦躁

最佳答案

您可以创建如下扩展方法:

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;
            }
        }
    }
}

例如,它可以像这样使用:

    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

这是你想要的吗?

关于c# - 在 Linq (C#) 中动态交叉连接多个不同大小的集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27328235/

相关文章:

C# 通过剪贴板保存然后检索数据

c# - ASP.Net WebAPI RC ILogger

c# - 用首次出现索引替换列表中 int 的有效方法

r - expand.grid 的非冗余版本

cartesian-product - 计算 Factor 中两个序列的笛卡尔积

c# - 为什么在 C# 中使用 finally?

c# - 如何使用 Entity Framework 6.1 返回 dataReader?

c# - 使用 Linq 的具有预定义类型的 GroupBy

c# - Linq 获取与条件匹配的索引列表以过滤另一个列表

relational-algebra - 关系代数中的笛卡尔积