【问题标题】:Dynamic Generation of All Possible Combinations of Index of an Array动态生成数组索引的所有可能组合
【发布时间】:2013-06-19 21:01:04
【问题描述】:

我的任务是生成数组的所有可能索引组合,其中数组可能是具有不同数量元素的单个、2D、3D、4D ... nD 数组。目前,我只能使用嵌套的 for 循环来支持单个、2D 和 3D 数组。

例子:

byte[,,] sampleArray = new byte[5,4,3];

Generated Index Combinations:
sampleArray[0,0,0]
sampleArray[0,0,1]
sampleArray[0,0,2]
sampleArray[0,1,0]
sampleArray[0,1,1]
sampleArray[0,1,2]
sampleArray[0,2,0]
sampleArray[0,2,1]
sampleArray[0,2,2]
sampleArray[0,3,0]
sampleArray[0,3,1]
sampleArray[0,3,2]
sampleArray[1,0,0]
sampleArray[1,0,1]
sampleArray[1,0,2]
sampleArray[1,1,0]
sampleArray[1,1,1]
sampleArray[1,1,2]
sampleArray[1,2,0]
sampleArray[1,2,1]
sampleArray[1,2,2]
sampleArray[1,3,0]
sampleArray[1,3,1]
sampleArray[1,3,2]
sampleArray[2,0,0]
sampleArray[2,0,1]
sampleArray[2,0,2]
sampleArray[2,1,0]
sampleArray[2,1,1]
sampleArray[2,1,2]
sampleArray[2,2,0]
sampleArray[2,2,1]
sampleArray[2,2,2]
sampleArray[2,3,0]
sampleArray[2,3,1]
sampleArray[2,3,2]
sampleArray[3,0,0]
sampleArray[3,0,1]
sampleArray[3,0,2]
sampleArray[3,1,0]
sampleArray[3,1,1]
sampleArray[3,1,2]
sampleArray[3,2,0]
sampleArray[3,2,1]
sampleArray[3,2,2]
sampleArray[3,3,0]
sampleArray[3,3,1]
sampleArray[3,3,2]
sampleArray[4,0,0]
sampleArray[4,0,1]
sampleArray[4,0,2]
sampleArray[4,1,0]
sampleArray[4,1,1]
sampleArray[4,1,2]
sampleArray[4,2,0]
sampleArray[4,2,1]
sampleArray[4,2,2]
sampleArray[4,3,0]
sampleArray[4,3,1]
sampleArray[4,3,2]

我的代码:

     protected void GenerateIndexCombinations(int indexCounter, 
     ref List<List<int>> indexList, Array arr, ref List<int> index)
        {
            int dimSize1 = arr.GetLength(0);
            int dimSize2 = 0;
            int dimSize3 = 0;
            if (indexCounter > 1)
            {
                dimSize2 = arr.GetLength(1);
                if (indexCounter > 2)
                {
                    dimSize3 = arr.GetLength(2);
                }
            }

            for (int a = 0; a < dimSize1; a++)
            {
                if (dimSize2 > 0)
                {
                    for (int b = 0; b < dimSize2; b++)
                    {
                        if (dimSize3 > 0)
                        {
                            for (int c = 0; c < dimSize3; c++)
                            {
                                index = new List<int>();
                                index.Add(a);
                                index.Add(b);
                                index.Add(c);
                                indexList.Add(index);
                            }
                        }
                        else
                        {
                            index = new List<int>();
                            index.Add(a);
                            index.Add(b);
                            indexList.Add(index);
                        }
                    }
                }
                else
                {
                    index = new List<int>();
                    index.Add(a);
                    indexList.Add(index);
                }
            }
        }

在哪里:
int indexCounter 是维数。
数组arr是使用反射访问的数组:

Array arr = fieldInfoArray[j].GetValue(_classInstance) as Array;


ref List&lt;List&lt;int&gt;&gt; indexList 将是组合的容器。
ref List&lt;int&gt; index 是添加到 indexList 中的个人编号。

由于维度大小以及每个维度的元素数量不固定,我想动态生成组合以替换我的嵌套 for 循环,有没有办法做到这一点?

感谢您的回答。

【问题讨论】:

    标签: c# visual-studio-2010


    【解决方案1】:

    Eric Lippert 有blogged 关于这个问题。在您的特定情况下,您正在寻找Enumerable.Range(0, 5)Enumerable.Range(0, 4)Enumerable.Range(0, 3) 的笛卡尔积。一般来说,你想要这样的东西:

    var dimensions = 
         Enumerable.Range(0, array.Rank)
                   .Select(r => Enumerable.Range(0, array.GetLength(r)));
    

    然后在dimensions 上调用Eric 的方法。在这里,我使用Array.Rank 获取矩阵的维数,然后使用Array.GetLength 获取沿每个维度的长度,然后动态生成我们需要计算笛卡尔积的序列。因此,对于每个维度,我们将该维度投影到沿该维度的有效索引序列array。因此,对于

    T[,,...,] array = new T[a_1, a_2, ..., a_n];
    

    我们最终得到dimensions 等于序列

    (Enumerable.Range(0, a_1),
     Enumerable.Range(0, a_2),
     .
     .
     .,
     Enumerable.Range(0, a_n)
    )
    
    using System.Linq;
    using System.Collections.Generic;
    using System;
    
    static class EnumerableExtensions {
        // credit: Eric Lippert
        public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
            this IEnumerable<IEnumerable<T>> sequences
        ) {
            IEnumerable<IEnumerable<T>> emptyProduct = 
                new[] { Enumerable.Empty<T>() };
            return sequences.Aggregate(
                emptyProduct,
                (accumulator, sequence) =>
                     from accseq in accumulator
                     from item in sequence
                     select accseq.Concat(new[] { item })
            );
        }
    }
    
    class Program {
        public static void Main(string[] args) {
            int[,,] array = new int[5, 4, 3];
            var dimensions = 
                Enumerable.Range(0, array.Rank)
                          .Select(r => Enumerable.Range(0, array.GetLength(r)));
            var indexes = dimensions.CartesianProduct();
            foreach(var index in indexes) {
                Console.WriteLine(String.Join(",", index));
            }
        }
    }
    

    【讨论】:

    • 嗨 Jason,我尝试使用博客中的代码,但仍然无法获得组合。抱歉,因为我是 C# 编码的新手。 :(
    • @Ron Reyes:很抱歉听到这个消息。我的代码与 Eric 的代码结合使用,但我仍然为您提供了完整的示例。
    • 好的,我再试试,就是不知道用Console.WriteLine怎么看结果。
    • @Ron Reyes:我不确定你的意思。在 Visual Studio 中,启动一个新的解决方案,使其成为控制台应用程序,然后将上面的代码完全粘贴。然后,编译并运行应用程序。
    • 它在输出中显示:System.Linq.Enumerable+d__71`1[System.Int32]
    猜你喜欢
    • 2022-01-18
    • 2016-08-16
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多