0

I want to simplify the generation of a List in C# using LINQ. My goal is to populate the new List with operations using values of another List. I'm willing to use 3rd party libraries, like Deedle or MathNet, if they can reproduce similar performance to my current solution.

A equivalent way to achieve my goal in Matlab would be using simple matrix operations and a dot operation as shown in the following code: dailyRetList = (dailyCloseList(2:end) - dailyCloseList(1:end-1))./dailyCloseList(1:end-1)

Which creates a new array iterating over dailyCloseList and for each element it subtracts dailyCloseList[i-1] from dailyCloseList[i], then divide the result by dailyCloseList[i-1] and finally push the value to the newly created array.

My current solution to tackle the problem is:

var dailyCloseList = new List<double>{11.8d, 11.7d, 13d, 12.6d, 15d};

var dailyRetList = new List<double>();
for (var i = 1; i < dailyCloseList.Count; i++)
{
     dailyRetList.Add((dailyCloseList[i] - dailyCloseList[i-1])/dailyCloseList[i-1]);
}
fadlio
  • 5
  • 3
  • Welcome to SO, could you provide your question with more details about your expected result, because is not clear what `dailyRetList = (dailyCloseList(2:end) - dailyCloseList(1:end-1))./dailyCloseList(1:end-1)` does. – Diego Osornio Jan 31 '19 at 23:27
  • Your current solution seems fine. Is there something wrong with it, or are you just looking to achieve the same result in less code? – Ben Jan 31 '19 at 23:37
  • @Ben Yeah, my solutions works but I'm just starting in C# and LINQ so I just wanna check if there is a way to write less code. – fadlio Jan 31 '19 at 23:44
  • I'm not sure. You could try this https://stackoverflow.com/questions/17227794/get-previous-record-to-current-one-using-linq but I suspect what you're currently doing is actually simply. – Ben Jan 31 '19 at 23:47
  • Why do you want to write less code? – thepirat000 Feb 01 '19 at 01:26
  • Just looking for options. Was my "laziness" that made me discover LINQ. – fadlio Feb 01 '19 at 01:38

3 Answers3

1

You can use this in Linq:

var m = Enumerable.Range(1, dailyCloseList.Count - 1)
                .Select(i => (dailyCloseList[i] - dailyCloseList[i - 1])/ dailyCloseList[i - 1])
                .ToList();

It always helps to check for DivideByZero exception.

Gauravsa
  • 6,330
  • 2
  • 21
  • 30
1

Another option is to use Zip:

var change = dailyCloseList.Zip(dailyCloseList.Skip(1))
                           .Select((x,y) => (y - x)/x)
                           .ToList(); 
D Stanley
  • 149,601
  • 11
  • 178
  • 240
0

I think the most Linq-way is this

var dailyRetList = dailyCloseList
    .ConsecutivePairs((a, b) => (b - a) / a)
    .ToList();

Sure, you have to define the ConsecutivePairs function (once somewhere). But unlike the Guaravsa solution, this works on IEnumerable, so does not need direct index access. But it all comes at a price. Your original simple loop is about 3x faster that any of the solutions using enumerations (btw you should preallocate the List at the beginning for best performance).

And the function implemenatiton, just for completeness:

public static IEnumerable<Q> ConsecutivePairs<T, Q>(this IEnumerable<T> sequence, Func<T, T, Q> selector)
{
    using(var en = sequence.GetEnumerator())
    {
        if (!en.MoveNext()) { yield break; }
        T prev = en.Current;
        while (en.MoveNext())
        {
            yield return selector(prev, en.Current);
            prev = en.Current;
        }
    }
}
Antonín Lejsek
  • 6,003
  • 2
  • 16
  • 18