4

I am new to lambda expression and I have problem to convert parts of code which involves indices of list inside the loop to equivalent lambda expression.

Example 1: Working with different indices inside one list

List<double> newList = new List<double>();
for (int i = 0; i < list.Count - 1; ++i)
{
     newList.Add(list[i] / list[i + 1]);
}

Example 2: Working with indices from two lists

double result = 0;
for (int i = 0; i < list1.Count; ++i)
{
    result += f(list1[i]) * g(list2[i]);
}

How to write equivalent lambda expressions?

mihai
  • 4,592
  • 3
  • 29
  • 42
Dejan
  • 966
  • 1
  • 8
  • 26
  • If it is not a query, IMHO, do not attempt to use LINQ (Q=query). It looks fascinating, but it is not suitable tool for kind of operations you mentioned above. Worst is, most folks don't know under the hood, and in some cases, end up with poor performance code, and code with unexpected behaviors. – Vikas Gupta Oct 13 '14 at 15:32
  • @VikasGupta can you elaborate more on what you mean? – Nyra Oct 13 '14 at 15:54
  • Just as a side node, you can use [implicit typing](http://msdn.microsoft.com/en-us/library/bb384061.aspx), that is: instead of `List newList = new List();` you can use `var newList = new List();` It's easier to read the code in the long run – mihai Oct 13 '14 at 16:05
  • @Mihai Tnx about that. I already knew it, but this is my old code written in time when I didn't know about implicit typing and lambda expressions. – Dejan Oct 13 '14 at 16:11
  • @alykins Comments is not a place where I can write a lot, but for start, I'd point to a question already asked and answered on SO. http://stackoverflow.com/questions/271384/pros-and-cons-of-linq-language-integrated-query – Vikas Gupta Oct 13 '14 at 16:45

2 Answers2

7

A lambda expression is something that looks like {params} => {body}, where the characteristic symbol is the => "maps to." What you are asking for are typically referred to as LINQ query expressions, which come in two styles:

  • The functional style of query is typically a sequence of chained calls to LINQ extension methods such as Select, Where, Take, or ToList. This is the style I have used in the examples below and is also the much-more prevalent style (in my experience).

  • The "language integrated" style (*) uses built-in C# keywords that the compiler will turn into the functional style for you. For example:

    var query = from employee in employeeList
                where employee.ManagerId == 17
                select employee.Name;
    
                    | compiler
                    v rewrite
    
    var query = employeeList
        .Where(employee => employee.ManagerId == 17)
        .Select(employee => employee.Name);
    

Example 1:

var newList = Enumerable.Range(0, list.Count - 1)
    .Select(i => list[i] / list[i + 1])
    .ToList();

Example 2:

var result = Enumerable.Zip(list1.Select(f), list2.Select(g), (a, b) => a * b).Sum();

(*) I'm not actually sure this is the official name for it. Please correct me with the proper name if you know it.

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • The question is answered here, but I'd add a warning, that IMHO, this turn code inside out way of doing a simple operation, makes code hard to read. LINQ, even though can be made to work here, it is not suitable for kind of operations being performed in the question. – Vikas Gupta Oct 13 '14 at 15:36
  • I guess the _functional_ style that you're referring to is called _fluent syntax_ and the second one, with the *, is _query syntax_. – mihai Oct 13 '14 at 15:40
  • This is exactly what I want. Can you just comment on @VikasGupta remark. Is your solution not suitable for this kind of operation? I would like to change my old code, and your solution looks elegant. – Dejan Oct 13 '14 at 16:09
  • @Petar Each of the LINQ methods is a little micro-algorithm. When you have a problem that can be concisely and *clearly* represented as a composition of these micro-algorithms, they're almost always appropriate. If you find yourself having to use "tricks" to accomplish your goal using these, it may be better to use the normal (imperative) style instead. In these two examples, I find the LINQ versions to be very straightforward, so I would use them. – Timothy Shields Oct 13 '14 at 16:26
  • @Petar isn't using `Zip` for the first example instead of `Enumerable` a lot cleaner? – mihai Oct 13 '14 at 16:39
  • @Petar Comments is not a place where I can write a lot, but for start, I'd point to a question already asked and answered on SO. http://stackoverflow.com/questions/271384/pros-and-cons-of-linq-language-integrated-query In current context, I'd emphasize "Query expressions aren't understood well enough, and are overused. Often simple method invocation is shorter and simpler.", "Without understanding what's going on, it's easy to write very inefficient code" (above code **is** inefficient, is must to know, even if acceptable), "Debugging can be very tricky due to deferred execution and streaming" – Vikas Gupta Oct 13 '14 at 16:40
  • @Mihai I upvoted your answer because it is certainly at least an equally good way to do it. In this case it's not an issue because the source is a list, but generally be careful zipping an enumerable with itself, because that will cause you to enumerate it twice, which might be undesirable in some circumstances. – Timothy Shields Oct 13 '14 at 16:44
  • @Petar Put another way, the statement "I have problem to convert parts of code which involves indices of list inside the loop to equivalent lambda expression." sounds like a flag to me.. because it doesn't sound like a real problem. If you are just trying to understand and learn, great.. If this is production code, I'd advise against changing the working, simple code to above answer. Note, I am not against LINQ. I love it, but personally I find above solution clever (as Timothy calls it "tricks"), but not elegant way of doing what needs to be done. (No offense meant to anyone) – Vikas Gupta Oct 13 '14 at 16:50
  • @VikasGupta Yes, this is production code, and I want to refactor it in order to use lambda expression. I do this because the other classes in project is full of lambda expression. So I want to my work be consistent with the rest, and also I want to learn lambda expressions during this refactor. – Dejan Oct 13 '14 at 17:24
1

For your first example you can try using Zip and Skip:

var result = list.Zip(list.Skip(1), (x, y) => x / y);

How does it work

If your initial list is {1, 2, 3}, then Skip(1) would result in {2, 3}; then Zip takes {1, 2, 3} and {2, 3} as inputs, and tells that, for each pair of numbers, it shall divide them. Repeat until there are no more elements in at least one list, and return the result as IEnumerable.

For the second example,

var result = list1.Zip(list2, (x, y) => f(x) * f(y)).Sum();
mihai
  • 4,592
  • 3
  • 29
  • 42
  • Your solution for the first example is shorter and looks more elegant then solution with `Enumerable`. However, solution with Enumerable is easier to understand to me, because we select indices and then apply `list[i] / list[i + 1]` which tells us exactly what are we dividing. In your solution, we need to think more about what is `x` and what is `y`. I am new in this area, and my opinion is subjective. I accept solution which I think it is more clear. – Dejan Oct 13 '14 at 17:19
  • Well, no, but, if you were to write the solution in a functional language like Haskell, for example, it would also be harder to understand than the `Enumerable` version. At least in the beginning. But in the long run, greater power is more comfortable. – mihai Oct 13 '14 at 17:37