将数组的维度作为参数传递给C#

时间:2015-05-20 19:10:46

标签: c#

我正在学习C#,我正在尝试实现一个多功能的RandomVar类以及一些计算常见统计数据的方法。我希望能够通过实例化维度N的新变量来从其组件形成任意联合概率RandomVariable,其中N被传递到构造函数中。我想将随机Var X实现为两个一维的双精度列表,而randomVar XY不是两个长度为n ^ 2的列表,而是作为double [] []类型的randomVar,否则仍然可以使用全部相同的方法(ExpectedValue,Covariance等)。

我在执行此操作时遇到了很多麻烦。除了第一个天真的方法(有很多复制和粘贴)之外,我已经尝试从一个基本的RandomVar类继承到一个JointRandomVar类 - 仍然有很多复制粘贴。现在我尝试将类RandomVar的概率和结果数组作为List类型的泛型 - 这会产生很多问题,因为我无法弄清楚如何以适应性的方式编写方法(The std_Dev方法一般不能迭代它所需要的方式 - 所以我需要一些灵活的方法来定义方法,这样如果随机Var的"维度是#2;那么std_Dev方法会做一个双循环,或者为迭代过程弄平数组)。

想要更有经验的程序员提供一些设计帮助 - 是否有概率/结果数组列出传递这样一个参数的最佳方法?

非常感谢你的帮助。

编辑:这是所有双打的代码版本,因此人们可以阅读它,因为未更新的版本似乎让人更加困惑。我希望能够让所有这些方法都适用于任何数组维度的double []类型的对象,并且可以使用_values和具有任何维度的_probs来实例化该类。

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chapter_3_GUI
{
    class RandomVar
    {
        private double[] _values;
        private double[] _probs;
        private double _mean;
        private double _stddev;
        private int _length;
        private double _evalue;

        public RandomVar(double[] values, double[] probs)
        {
            _values = values;
            _probs = probs;
            _mean = meanCalc(_values);
            _stddev = stddevCalc(_values, _mean);
            _length = _values.Length;
            _evalue = expectedVal(_probs, _values, _length);
        }

        public double[] Values
        {
            get { return _values; }
            set { _values = value; }
        }

        public double Mean
        {
            get { return _mean; }
        }

        public double Stdev
        {
            get { return _stddev; }
        }

        public static double meanCalc(double[] var)
        {
            double mean = var.Sum();
            return mean;
        }

        public static double stddevCalc(double[] var, double mean)
        {
            double[] varianceArr = new double[var.Length];
            for (int i = 0; i <= var.Length; i++)
                varianceArr[i] = (var[i] - mean) * (var[i] - mean);
                double variance = varianceArr.Sum();
                double stddev = Math.Sqrt(variance);
                return stddev;
            { 

            }
        }

        public static double[][] multiplyProbs(RandomVar X, RandomVar Y, double[][] cprobMatrix)
        {
            double[][] probArr = new double[X._length][Y._length];
            for (int i=0; i <= probArr.Length; i++)
            {
                for (int j =0; j <= probArr.Length; j++)
                {
                    probArr[i][j] = Y._probs[j] * cprobMatrix[i][j];
                }
            }
            return probArr;
        }

        public static RandomVar multiplyVars(RandomVar X, RandomVar Y, Func<double,double> f)
        {
            double[][] productArr = new double[X._length][Y._length];
            for (int i=0; i<= productArr.Length; i++)
            {
                for (int j=0; j <= productArr.Length; i=j++)
                {
                    productArr[i][j] = f(X._values[i], Y._values[j]);
                }
            }
            double[][] probArr = multiplyProbs(X, Y, cprobMatrix);
            RandomVar product = new RandomVar(productArr, probArr);
            return product;
        }

        public static double expectedVal(double[] _probs, double[] _values, int _length)
        {
            double[] expectedArr = new double[_length];
            for (int i = 0; i <= expectedArr.Length; i++)
            {
                expectedArr[i] = _probs[i] * _values[i];
            }
            double evalue = expectedArr.Sum();
            return evalue;

        }

        public static double covarianceCalc(RandomVar X, RandomVar Y, Func<double, double> f)
        {
            RandomVar VarXY = multiplyVars(X, Y, f);
            double correlation = expectedVal(VarXY._probs, VarXY._values, VarXY._length);
            double covariance = correlation - (X._mean * Y._mean);
            return covariance;
        }

    }
}

1 个答案:

答案 0 :(得分:0)

每个维度的基数是否相同?您对“将其视为一个长大小的数组n ^ k”的评论表明它是。也就是说,n是每个维度中值/概率对的长度。

我的另一个问题是,在两个不同的数组中传递值和概率背后的原因是什么?如果是我,我会声明包含对的struct,例如:

struct ValueProbPair
{
    public readonly double Value;
    public readonly double Probability;

    public ValueProbPair(double value, double probability)
    {
        Value = value;
        Probability = probability;
    }
}

最后,就您的具体问题而言......嗯,目前还不清楚具体的问题是什么。您似乎有一个关于实现此目的的灵活方式的广泛的问题。

在我看来,这里面临的最大挑战(即具有最不直观明显的解决方案的障碍)是你问题的标题:

  

将数组的维度作为参数传递

您可以使用Array.CreateInstance(Type, int[])重载来执行此操作,即创建适当的数组对象。恕我直言,如果(但不要求)你可以将价值/概率对合并为一个struct,它也会更好。

另一个重要的警告是,您将无法获得编译器优化来访问数组元素的好处。你必须使用例如GetValue()方法,它很可能会阻止编译器直接访问数组元素(理论上这种优化是可行的,但对我来说似乎不太可能)。

因此,例如,您可以执行以下操作:

Array Combine(ValueProbPair[] newDimension, Array previousDimensions)
{
    int[] rankLengths = new int[previousDimensions.Rank + 1];

    for (int j = 0; j < previousDimensions.Rank; j++)
    {
        rankLengths[j] = previousDimensions.GetLength(j);
    }

    rankLengths[previousDimensions.Rank] = newDimension.Length;

    Array result = Array.CreateInstance(typeof(ValueProbPair), rankLengths);

    // then fill in your matrix using GetValue and SetValue to
    // access individual array elements...

    // Finally, return the new multi-dimensional array:
    return result;
}

访问元素使用params数组参数的各种数组方法重载,因此您可以毫不费力地编写可以处理任意维矩阵的代码。 E.g:

IEnumerable<double> GetAllValues(Array source)
{
    int[] index = new int[source.Rank];

    while (true)
    {
        yield return (double)source.GetValue(index);

        int j = 0;
        while (++index[j] == source.GetLength(j))
        {
            index[j] = 0;
            if (++j == index.Length)
            {
                yield break;
            }
        }
    }
}

最后一点注意:为了处理价值/概率,根据您的情况,您可能会发现使用词典完成所有这些操作更有意义。有不同的复杂情况,但基本构建块为Dictionary<double, object>,其中值为double或另一个Dictionary<double, object>。那么如果你正在寻找例如合并概率,您不必扫描值列表,而是可以直接查找它们作为字典中的键。