3
\$\begingroup\$

I'm going through C# Operators which led me to more specifically Lambda Expressions (C# Programming Guide). I've modified one of the examples from just getting the .Count to printing out the odd numbers. Is there anything I can do to simplify my code? Should I "method chain" oddNumbers and oddDescending together? I've left them apart since I'm just learning and seeing them separate is easier for me to understand right now.

class Program
{
    public static void Main(string[] args)
    {
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
        var oddNumbers = numbers.Where(x => x % 2 == 1);
        var oddDescending = oddNumbers.OrderByDescending(x => x);

        foreach (int odd in oddDescending)
        {
            Console.WriteLine(odd);
        }
    }
}
\$\endgroup\$
1
  • 2
    \$\begingroup\$ I would chain them, but keep them on separate lines. This would actually make it easier for me to read it because there wouldn't be a lot of fluff defining new variables and accessing them. \$\endgroup\$
    – user34073
    Apr 29 '17 at 0:51
6
\$\begingroup\$

People will commonly create an Extension method for IEnumerable to add a map method that behaves much like the IList<T>.ForEach method.

public static class IEnumerableExtensions {
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
        foreach(item in source) action(item);
    }
}

With this in hand, you can go all out on your filter & map.

class Program
{
    public static void Main(string[] args)
    {
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        numbers.Where(IsOdd)
                .OrderByDescending(x => x)
                .ForEach(Console.WriteLine);
     }

     private static bool IsOdd(int x) => x % 2 == 1;
}

Note that I did extract a method so we could name the filter. It makes it a bit more readable (and as an added bonus, reusable).

You may be asking yourself why naming the predicate is better than using a variable. Other than reuse, the benefit is that there's no need to store any state. At its heart, Linq is a functional way to program, so it's good to embrace it.

\$\endgroup\$
9
  • \$\begingroup\$ Btw, if you're interested in FP, another useful method is public static <T> Identity(<T> x) => x; "The Identity function" is the name of the lambda expression you're passing to OrderByDescending and is central to the concept of monads. \$\endgroup\$
    – RubberDuck
    Apr 29 '17 at 3:12
  • \$\begingroup\$ I've both heard and read about Extension methods before. Since I'm new to programming I don't fully understand how they work. Do you know of any article that explains them using layman's term that a newcomer could more easily understand? \$\endgroup\$
    – IvenBach
    Apr 29 '17 at 3:34
  • \$\begingroup\$ An extension method is just syntax sugar. It's completely equivalent to passing an arg to a static method. For example, IEnumerableExtensions.ForEach(numbers, Console.WriteLine). Try it out. Set a break point and step into it. You'll see what I mean. \$\endgroup\$
    – RubberDuck
    Apr 29 '17 at 3:47
  • \$\begingroup\$ Just did so. I'm confused that public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) has 2 parameters but only 1 .ForEach(Console.WriteLine); is passed and it still works. The this keyword ... is also used as a modifier of the first parameter of an extension method. explains why this works. This will take me a while to digest. I'll work on this and come back with more questions. Thanks for showing me something new. \$\endgroup\$
    – IvenBach
    Apr 29 '17 at 4:40
  • \$\begingroup\$ It's just syntax sugar. It compiles down to a regular static method that takes two params. \$\endgroup\$
    – RubberDuck
    Apr 29 '17 at 5:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.