在Linq(C#)中将多个不同大小的集合动态交叉连接在一起 [英] Dynamically cross-join multiple different-size collections together in Linq (C#)

查看:98
本文介绍了在Linq(C#)中将多个不同大小的集合动态交叉连接在一起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有未知数量的存储桶(集合),并且每个存储桶都有未知数量的实体

I have an unknown number of buckets(collections), and each bucket having an unknown number of entities

我需要产生所有实体的笛卡尔积,以便最终得到一个具有实体数组的COLLECTION,并且在每个数组中,每个存储桶中都有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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆