-1

I'm trying to find out if there is a way to create a loop for my example code below

// 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);

I'm trying to get something similar to the below pseudo code. Please keep in mind that each var item is a list of decimals

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

More information:

ListCalculationData is a list of my custom class that I have added below. What I'm trying to do is cycle through each variable in that class and perform a select query to perform the goodness of fit rsquared calculation on the list of decimals that the select query returns so it simplifies my code and makes it similar to my pseudo code

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

Update: I tried this for a local function and it fails with ; expected and invalid {

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

Update 2: This is what I have my current code set to because of the recommendations but obviously this doesn't work because it says that the name i doesn't exist in this context at this section: nameof(i.Ema12) and also because I'm using mostly pseudo code

 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)
           }
     }
  }
DarthVegan
  • 1,719
  • 7
  • 25
  • 42
  • 1
    Without more context, your question is too broad. A single `Select()` could return an enumeration of tuples instead of individual values. But you'd still need to call `RSquared()` multiple times, with a `Select()` _there_ to extract the tuple value again. I don't see that helping much. In your loop example, you're going the other way, but you would need reflection or a pre-filled array of accessor delegates to get the property/field value you're trying to get. It would help if you'd include a good [mcve] and explain better what you've tried and what _specific_ trouble you're having. – Peter Duniho Sep 12 '17 at 00:29
  • @PeterDuniho I added more information that I hope clarifies things for you – DarthVegan Sep 12 '17 at 00:37
  • The question gets messier and messier. Can you take a look at for example https://dotnetfiddle.net/Sb65DZ and see if it makes sense to you? – Jimmy Sep 14 '17 at 22:42

3 Answers3

1

You can either express each individual field as a lambda that retrieves a particular field value (I think this is better) or as a string or PropertyType value that uses reflection to achieve the same thing.

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

Then it's just a matter of getting each individual IEnumerable<double> sequence and calculating its RSquared value.

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


From comments:

This is similar to what I'm looking for but I have over 40 variables in my class and I added more information to try to explain what I'm trying to do but I'm trying to prevent the extra 40 lines of code to do something similar to your code

The following should do what you're asking, using reflection.

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

Edit: The question was edited again, and I'm no longer certain you need the indirection of the getters. see https://dotnetfiddle.net/Sb65DZ for a barebones example of how I'd write this code.

Jimmy
  • 89,068
  • 17
  • 119
  • 137
  • This is similar to what I'm looking for but I have over 40 variables in my class and I added more information to try to explain what I'm trying to do but I'm trying to prevent the extra 40 lines of code to do something similar to your code – DarthVegan Sep 12 '17 at 00:39
  • @user3610374: you can use reflection and the `Expression` class to dynamically generate the delegate instances the above answer uses. There will be a one-time up-front cost to generate the delegates, but once that's done, the calculation will be just as efficient as the above. – Peter Duniho Sep 12 '17 at 00:40
  • @PeterDuniho I'm afraid I'm not familiar with that. Do you have a short example of what you are talking about or a reference article? – DarthVegan Sep 12 '17 at 00:42
  • You can search Stack Overflow. But here are a couple of related examples: https://stackoverflow.com/questions/40263509/generic-method-to-get-property-values-with-linq-expression-and-reflection and https://stackoverflow.com/questions/5075484/property-selector-expressionfunct-how-to-get-set-value-to-selected-property. These example use lambdas to populate the expressions; you'll need to use reflection instead to get the `PropertyInfo` object used in the expression tree. But the basic idea is the same. – Peter Duniho Sep 12 '17 at 00:45
  • @user3610374 I added an example of how you could use reflection to do this. This will incur some reflection overhead each run compared with peterduniho's suggestion of dynamically compiling delegates, but I generally claim YAGNI to more complex metaprogramming until benchmarking proves otherwise. – Jimmy Sep 12 '17 at 22:25
0

In Visual Studio 2015+ you can use local functions (not tested):

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

or a bit less efficient 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);

Another alternative could be converting them to array:

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

To find the property with the max rsquared value using reflection, you can try this:

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;
Slai
  • 22,144
  • 5
  • 45
  • 53
  • I like the array alternative but is there a possible way to see which variable returns the highest goodnessoffit rsquared value? – DarthVegan Sep 12 '17 at 01:49
  • @user3610374 the array alternative is pretty much the same as the other answer. You can try the reflection example, but keep in mind that reflection is much slower (not sure how much) than making array with lambdas for each property. – Slai Sep 12 '17 at 02:30
  • I prefer the array alternative but I need a way to find which variable has the highest value – DarthVegan Sep 12 '17 at 02:33
  • Are you able to add more lines to the local function? – DarthVegan Sep 13 '17 at 02:28
  • @user3610374 sure, if you use `{}` like in regular method. – Slai Sep 13 '17 at 02:46
  • @user3610374 you can define local functions the same way as regular functions `double r(Func f) { return GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f), vectorArray); };`. – Slai Sep 13 '17 at 21:41
  • One final question. Would I have to create a second local function to handle lists of decimals that I also have in that same class and if so then do I just change Func f to Func> f – DarthVegan Sep 13 '17 at 21:56
  • @user3610374 not sure if I understand, but you can have a generic local function like `T r(Func f) { return GoodnessOfFit.RSquared(calc.ListCalculationData.Select(f), vectorArray); };`. BTW, you don't have to use local function. I think the more common approach is to make is to make regular non-local function, but it will need another parameter for the list. – Slai Sep 13 '17 at 22:10
  • Ok I edited my post again to show my latest code including my pseudo code and hopefully it will show you what I'm trying to do. I'm trying to basically run this code once so that I can do it for all decimal values in my custom class instead of writing hundreds of lines – DarthVegan Sep 14 '17 at 00:32
0

You could use an extension method to collect a common sequence of operations together.

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

called by

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);
Amy B
  • 108,202
  • 21
  • 135
  • 185