有没有办法用循环或linq语句简化这个?

时间:2017-09-12 00:16:33

标签: c# linq

我试图找出是否有办法为我的示例代码创建一个循环

// the objects below create a list of decimals
var ema12 = calc.ListCalculationData.Select(i => (double)i.Ema12);
var ema26 = calc.ListCalculationData.Select(i => (double)i.Ema26);
var ema = calc.ListCalculationData.Select(i => (double)i.Ema);
var adl = calc.ListCalculationData.Select(i => (double)i.ADL);

var r1 = GoodnessOfFit.RSquared(ema12);
var r2 = GoodnessOfFit.RSquared(ema26);
var r3 = GoodnessOfFit.RSquared(ema);
var r4 = GoodnessOfFit.RSquared(adl);

我正在尝试获得类似于以下伪代码的内容。请记住,每个var项都是小数列表

foreach (var item in calc.ListCalculationData.AsEnumerable())
{
    var item2 = calc.ListCalculationData.Select(i => (double)item);
    var r1 = GoodnessOfFit.RSquared(item2);
}

更多信息:

ListCalculationData是我在下面添加的自定义类的列表。我正在尝试做的是循环遍历该类中的每个变量并执行选择查询以在select查询返回的小数列表上执行拟合优度计算,这样可以简化我的代码并使其类似于my伪代码

public class CalculationData
    {
        public decimal Ema { get; set; }
        public decimal Ema12 { get; set; }
        public decimal Ema26 { get; set; }
        public decimal ADL { get; set; }
    }

更新:我尝试了本地功能,它失败了;预期和无效{

double r(Func<CalculationData, double> f) =>
{ GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f), vectorArray) };

更新2:这是我现有的代码设置因为建议,但显然这不起作用,因为它说在这个上下文中我不存在名称:nameof(i.Ema12 )还因为我主要使用伪代码

 MultipleRegressionInfo rn(Func<CalculationData, double> f, string name, int days)
                            {

 MultipleRegressionInfo mrInfo = new MultipleRegressionInfo
                            {
                                RSquaredValue = GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f), vectorArray),
                                ListValues = (List<double>)calc.ListCalculationData.Select(f).ToList(),
                                ValueName = name,
                                Days = days
                            };
                            listMRInfo.Add(mrInfo);

                            return mrInfo;
                        };

  MultipleRegressionInfo rnList(Func<CalculationData, List<decimal>> f, string name, int days)
                            {

 MultipleRegressionInfo mrInfo = new MultipleRegressionInfo
                            {
                                RSquaredValue = GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f), vectorArray),
                                ListValues = (List<double>)calc.ListCalculationData.Select(f).ToList(),
                                ValueName = name,
                                Days = days
                            };
                            listMRInfo.Add(mrInfo);

                            return mrInfo;
                        };

  foreach (CalculationData calc in ListCalculationData)
  {
     foreach (object value in calc)
     {
           if (value == typeof(decimal))
           {
                MultipleRegressionInfo r1 = rn(i => (double)i.value, nameof(i.value), 100)
           }
           else if (value == typeof(List<decimal>)
           {
                MultipleRegressionInfo r1 = rnList(i => i.value, nameof(i.value), 100)
           }
     }
  }

3 个答案:

答案 0 :(得分:1)

您可以将每个单独的字段表示为检索特定字段值的lambda(我认为这样更好),或者将字符串或PropertyType值表示为使用反射来实现相同的事物。

    var getters = new Func<CalculationData, double>[] {
        (i) => (double)i.Ema12,
        (i) => (double)i.Ema26,
        (i) => (double)i.Ema,
        (i) => (double)i.ADL,
    };

然后,只需获取每个IEnumerable<double>序列并计算其RSquared值即可。

    var dataseries = getters.Select((func) => calc.ListCalculationData.Select(func));
    double[] results = dataseries.Select((data) => GoodnessOfFit.RSquared(data)).ToArray();

<小时/> 来自评论:

  

这与我正在寻找的类似,但我的课程中有40多个变量,我添加了更多信息,试图解释我尝试做什么,但我试图尝试防止额外的40行代码执行与您的代码类似的操作

以下内容应该使用反射进行您所要求的操作。

 IEnumerable<Func<CalculationData, double>> getters =
     typeof(CalculationData).GetProperties()
     .Select<PropertyInfo, Func<CalculationData, double>>(
         (PropertyInfo p) => (CalculationData x) => (double)(decimal)p.GetValue(x)
     );

编辑:问题再次被编辑,我不再确定你需要间接的getter。请参阅https://dotnetfiddle.net/Sb65DZ,了解我如何编写此代码的准确示例。

答案 1 :(得分:0)

在Visual Studio 2015+中,您可以使用local functions(未经测试):

double r(Func<CalculationData, double> f) => 
                               GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f)); 

double r1 = r(i => (double)i.Ema12), r2 = r(i => (double)i.Ema26), 
       r3 = r(i => (double)i.Ema)  , r4 = r(i => (double)i.ADL);

或效率稍低的lambda:

Func<Func<CalculationData, double>, double> r = f =>                      
                               GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f)); 

double r1 = r(i => (double)i.Ema12), r2 = r(i => (double)i.Ema26), 
       r3 = r(i => (double)i.Ema)  , r4 = r(i => (double)i.ADL);

另一种选择可能是将它们转换为数组:

Func<CalculationData, double>[] lambdas = { i => (double)i.Ema12, i => (double)i.Ema26, 
                                            i => (double)i.Ema,   i => (double)i.ADL };

double[] r = Array.ConvertAll(lambdas, f =>                     
                               GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f))); 

要使用反射查找具有max rsquared值的属性,您可以尝试:

Tuple<double, string> maxR = typeof(CalculationData).GetProperties().Max(p => Tuple.Create(
    GoodnessOfFit.RSquared(calc.ListCalculationData.Select(i => Convert.ToDouble(p.GetValue(i)))), p.Name));

double maxRvalue = maxR.Item1;
string maxRname = maxR.Item2;

答案 2 :(得分:0)

您可以使用扩展方法一起收集常见的操作序列。

public static class CalculationDataExtensions
{
  public static IEnumerable<double> CalcRSquared(
    this IEnumerable<CalculationData> source,
    Func<CalculationData, decimal> propertySelector)
  {
    IEnumerable<double> values = source
      .Select(propertySelector)
      .Select(x => (double)x);

    return GoodnessOfFit.RSquared(values);
  }
}

通过

调用
var r1 = calc.ListCalculationData.CalcRSquared(x => x.Ema12);
var r2 = calc.ListCalculationData.CalcRSquared(x => x.Ema26);
var r3 = calc.ListCalculationData.CalcRSquared(x => x.Ema);
var r4 = calc.ListCalculationData.CalcRSquared(x => x.ADL);