Page 1 of 1

LINQ by Example 2: Enumerable Methods M-Z

#1 andrewsw  Icon User is online

  • It's just been revoked!
  • member icon

Reputation: 3838
  • View blog
  • Posts: 13,595
  • Joined: 12-December 12

Posted 25 August 2014 - 11:19 AM

Enumerable Methods A-L
Methods Using IEqualityComparer
Query Expression Syntax
LINQ to XML Querying

Max and Min

Returns the maximum/minimum value in a sequence of values.

I am treating these two methods together. My examples use Max, just replace with the word Min for those examples.

There are 22 overloads for both Max and Min. There are versions for the different data-types Decimal, Double, Int32, Int64 and Single, and nullable versions of each of these. (int? x declares an integer that can be assigned 'null'.) There are essentially three different versions.
    int largeNos = nos.Max();
    Console.WriteLine("Max number is {0}", largeNos); // 50
    decimal largeSalary = staff.Max(x => x.salary);
    Console.WriteLine("Max salary is {0:C}", largeSalary); // £28,000.00
    decimal minSalary = staff.Min(x => x.salary);
    Console.WriteLine("Min salary is {0:C}", minSalary); // £18,000.00


Max: Invokes a transform function on each element of a sequence and returns the maximum (type) value.
    decimal salaryByLen = staff.Max(member => member.salary * member.name.Length);
    Console.WriteLine("Max salary x name-length: {0}", salaryByLen); //324000 = 12 * 27000


Max<TSource> Method (IEnumerable<TSource>): Returns the maximum value in a generic sequence. The objects, or their type, need to implement IComparable. See the docs.

Min (see 'Max and Min')

OfType

Filters the elements of an IEnumerable based on a specified type.

The OfType<TResult>(IEnumerable) method returns only those elements in source that can be cast to type TResult. To instead receive an exception if an element cannot be cast to type TResult, use Cast<TResult>(IEnumerable).
    System.Collections.ArrayList fruits = new System.Collections.ArrayList{ 
        "Apple", 24, "Pear", "Banana", 50 };
    int sumFruit = fruits.OfType<int>().Sum();
    Console.WriteLine("Sum of fruits (int) is {0}", sumFruit); // 74

    int countFruit = fruits.OfType<string>().Count();
    Console.WriteLine("Count of fruits (string) is {0}", countFruit); // 3


OrderBy and OrderByDescending

Sorts the elements of a sequence in ascending/descending order. See also ThenBy and ThenByDescending.

OrderBy/Descending 1: Sorts the elements of a sequence in ascending/descending order according to a key.
    var staffList = staff.OrderBy(member => member.name.Split(' ')[1]);
    // (order by lastname)
    foreach (var person in staffList) {
        string[] names = person.name.Split(' ');
        Console.WriteLine("{0}, {1} (salary) {2:C}", names[1], names[0], person.salary);
    }
    //Bones, Bob (salary) £20,000.00
    //Diddly, Dave (salary) £28,000.00
    //Elbow, Liz (salary) £22,500.00
    //Muggins, Mary (salary) £22,000.00
    //Piccalilli, Robert (salary) £18,000.00
    //Pickles, Mary (salary) £27,000.00

    var staffListBySalDesc = staff.OrderByDescending(member => member.salary);
    foreach (var person in staffList) {
        string[] names = person.name.Split(' ');
        Console.WriteLine("{0}, {1} (salary) {2:C}", names[1], names[0], person.salary);
    }
    //Bones, Bob (salary) £20,000.00
    //Diddly, Dave (salary) £28,000.00
    //Elbow, Liz (salary) £22,500.00
    //Muggins, Mary (salary) £22,000.00
    //Piccalilli, Robert (salary) £18,000.00
    //Pickles, Mary (salary) £27,000.00


OrderBy/Descending 2: Sorts the elements of a sequence in ascending/descending order by using a specified comparer.

Create these two IComparer classes for the examples that follow:
    public class CompareStrings : IComparer<string> {
        public int Compare(string x, string y) {
            return string.Compare(x, y, true);
            // true means ignoreCase
        }
    }

    public class CompareIntegers : IComparer<int> {
        public int Compare(int x, int y) {
            return x - y;
        }
    }


When comparing two strings or integers these classes return -1 if the first value is less than the second, 0 if they are the same, and 1 if the second is greater than the first.

IComparer<T> Interface :MSDN

MSDN said:

Defines a method that a type implements to compare two objects.

    IEnumerable<string> rainbowCompare = rainbow.OrderBy(
        bow => bow, new CompareStrings());
    // case-insensitive sort, modify the rainbow array to test
    foreach (string bow in rainbowCompare) {
        Console.WriteLine(bow);
    }

    IEnumerable<string> rainbowCompareLength = rainbow.OrderBy(
        bow => bow.Length, new CompareIntegers());
    // sort by string-length
    foreach (string bow in rainbowCompareLength) {
        Console.WriteLine(bow);
    }


OrderByDescending (see 'OrderBy and OrderByDescending')

Range

Range(start, count): Generates a sequence of integral numbers within a specified range.

Generates count integers starting at start. (See 1st reply below.)
    IEnumerable<int> squares = Enumerable.Range(1, 4).Select(x => x * x);
    // Select() is not necessary if you just want an integer sequence.
    foreach (int square in squares) {
        Console.Write("{0} ", square);  // 1 4 9 16
    }
    Console.WriteLine();


Repeat

Repeat(element, count): Generates a sequence that contains one repeated value.
    IEnumerable<string> liking = Enumerable.Repeat("I love LINQ", 5);
    foreach (string msg in liking) {
        Console.WriteLine(msg);
    }


Reverse

Inverts the order of the elements in a sequence.
    IEnumerable<string> wobniar = rainbow.Reverse();
    foreach (string item in wobniar) {
        Console.Write("{0} ", item);
    }
    // George Zippy Bungle Freddy Jane Rod
    Console.WriteLine();


Select

Select 1: Projects each element of a sequence into a new form.
    IEnumerable<string> fullnames = staff.Select(x => 
        x.name.Split(' ')[1] + ", " + x.name.Split(' ')[0]);

    foreach (string name in fullnames) {
        Console.WriteLine(name);
    }
    //Bones, Bob
    //Muggins, Mary
    //Elbow, Liz
    //Diddly, Dave
    //Pickles, Mary
    //Piccalilli, Robert


Select 2: Projects each element of a sequence into a new form by incorporating the element's index.

Examples for methods that incorporate the index tend to be slightly artifical. The index is most useful when returning a string which incorporates a row-number.
    var salaryTimes = staff.Select((member, index) =>
        new { index, times = member.salary * index });

    foreach (var item in salaryTimes) {
        Console.WriteLine("Item {0}, value {1:c}", item.index, item.times);
    }
    //Item 0, value £0.00
    //Item 1, value £22,000.00
    //Item 2, value £45,000.00
    //Item 3, value £84,000.00
    //Item 4, value £108,000.00
    //Item 5, value £90,000.00


SelectMany

Projects each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence.

The examples use this new array:
    var pupils = new[] { new { name = "Dave", grades = new[] { 'A', 'A', 'C' } },
        new { name = "David", grades = new[] { 'A', 'A', 'C' } },
        new { name = "Peter", grades = new[] { 'A', 'B', 'C' } },
        new { name = "Philip", grades = new[] { 'B', 'B', 'E' } },
        new { name = "Jane", grades = new[] { 'B', 'C', 'C' } }
    };


SelectMany 1 (of 4): Projects each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence.
    IEnumerable<char> allGrades = pupils.SelectMany(pupil => pupil.grades);
    Console.WriteLine(string.Join(" ", allGrades));
    // A A C A A C A B C B B E B C C
    Console.WriteLine(string.Join(", ", 
        pupils.SelectMany(pupil => pupil.grades).Distinct().OrderBy(x => x)));
    // A, B, C, E

    // This can also be achieved with Select and two foreach loops:
    IEnumerable<char[]> selectGrades = pupils.Select(pupil => pupil.grades);
    foreach (char[] item in selectGrades) {
        foreach (char ch in item) {
            Console.Write(ch + " ");
        }
    }


SelectMany 2: Projects each element of a sequence to an IEnumerable<T>, and flattens the resulting sequences into one sequence. The index of each source element is used in the projected form of that element.
    IEnumerable<string> gradesIndexed = pupils.SelectMany((pupil, index) =>
        pupil.grades.Select(grade => (index+1) + " " + grade));
    foreach (string item in gradesIndexed) {
        Console.WriteLine(item + " ");
    }
    // 1 A 1 A 1 C 2 A 2 A 2 C 3 A 3 B 3 C 4 B 4 B 4 E 5 B 5 C 5 C 


SelectMany 3: Projects each element of a sequence to an IEnumerable<T>, flattens the resulting sequences into one sequence, and invokes a result selector function on each element therein.
    var pupilGrades = pupils.SelectMany(pupil => pupil.grades,
        (Pupil, Grade) => new { Pupil, Grade })
        .Where(x => x.Grade > 'A')
        .Select(y => new { ThePupil = y.Pupil, TheGrade = y.Grade });

    foreach (var pg in pupilGrades) {
        Console.WriteLine(pg.ThePupil.name + " " + pg.TheGrade);
    }
    //Peter B
    //Peter C
    //Philip B
    //Philip B
    //Philip E
    //Jane B
    //Jane C
    //Jane C


SelectMany 4: Projects each element of a sequence to an IEnumerable<T>, flattens the resulting sequences into one sequence, and invokes a result selector function on each element therein. The index of each source element is used in the intermediate projected form of that element. the docs

SequenceEqual

SequenceEqual 1: Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type.
    string[] rainbow2 = new string[rainbow.Length];
    Array.Copy(rainbow, rainbow2, rainbow.Length);
    Console.WriteLine("Rainbows equal? {0}", rainbow.SequenceEqual(rainbow2) ? "yes" : "no"); // yes
    rainbow[0] = "Rodney";
    Console.WriteLine("Rainbows equal? {0}", rainbow.SequenceEqual(rainbow2) ? "yes" : "no"); // no
    rainbow[0] = "Rod";


SequenceEqual 2: Determines whether two sequences are equal by comparing their elements by using a specified IEqualityComparer<T>. See Part 3.

Single

Returns a single, specific element of a sequence.

Single 1: Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
    try {
        string justTheOne = rainbow.Single();
        Console.WriteLine("There is only one member of 'rainbow'.");
    } catch (System.InvalidOperationException) {
        Console.WriteLine("There isn't just a single element.");
    }


Single 2: Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.
    try {
        string oneGT27k = staff.Single(member => member.salary > 27000).name;
        Console.WriteLine("There is only one member earning > 27k, {0}.", oneGT27k);
        // Dave Diddly
    } catch (System.InvalidOperationException) {
        Console.WriteLine("No one earn's more then 27k.");
    }


SingleOrDefault

SingleOrDefault 1: Returns the only element of a sequence, or a default value if the sequence is empty. This method throws an exception if there is more than one element in the sequence.
    int[] pageNumbers = { };
    int startPage = pageNumbers.SingleOrDefault();
    // the default would be 0, but page numbering should start from 1..
    startPage = (startPage == 0) ? 1 : startPage;
    // or use DefaultIfEmpty..
    int startPagev2 = pageNumbers.DefaultIfEmpty(1).Single();
    Console.WriteLine("Compare start page: {0} {1}", startPage, startPagev2);


SingleOrDefault 2: Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists. This method throws an exception if more than one element satisfies the condition.
    try {
        string justLength3 = rainbow.SingleOrDefault(name => name.Length == 6);
        // if no matches, variable would be an empty string
        Console.WriteLine("Single person whose name has length 3: {0}", justLength3);
    } catch (System.InvalidOperationException) {
        // or ArgumentNullException for null source or predicate
        Console.WriteLine("More than one match.");
    }


Skip

Bypasses a specified number of elements in a sequence and then returns the remaining elements.

The Take<TSource> and Skip<TSource> methods are functional complements.
    IEnumerable<int> nosBeyond3 = nos.OrderByDescending(x => x).Skip(3);
    Console.WriteLine("Knock off the top 3 numbers:");
    foreach (int num in nosBeyond3) {
        Console.Write(num + " ");
    }       // 34 34 32 31 22 22 21 17 10
    Console.WriteLine();

    var salsBeyond3 = staff.OrderByDescending(x => x.salary).Skip(3);
    Console.WriteLine("Knock off the top 3 salaries:");
    foreach (var member in salsBeyond3) {
        Console.Write("{0:C} ", member.salary);
    }       // £22,000 £20,000 £18,000
    Console.WriteLine();


SkipWhile

Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.

The TakeWhile and SkipWhile methods are functional complements.

SkipWhile 1: Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.
 
    IEnumerable<int> nosLT30 = nos
        .OrderByDescending(x => x)
        .SkipWhile(x => x >= 30);
    foreach (int num in nosLT30) {
        Console.Write("{0} ", num);
    }       // 22 22 21 17 10
    Console.WriteLine();


SkipWhile 2: Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. The element's index is used in the logic of the predicate function.
    IEnumerable<int> skippy = nos
        .SkipWhile((x, index)  => x > 5  * index);
    foreach (int num in skippy) {
        Console.Write("{0} ", num);
    }       // 34 40 50 10 17


Sum

Computes the sum of a sequence of numeric values.

There are 20 overloads of this method, for the data-types Decimal, Double, Int32, Int64 and Single, and nullable versions of each of these. So there are essentially 2 (or 3, if you count the nullable versions) different versions of this method.
    int totalSum = nos.Sum();
    Console.WriteLine("Sum of numbers is {0}", totalSum); // 353

    // skips null values
    int?[] nosWithNull = { 10, null, 40, 20 };
    int? totalNulls = nosWithNull.Sum();
    Console.WriteLine("Sum of numbers is {0}", totalNulls); // 70


Sum 2 (or 3): Computes the sum of the sequence of (type) values that are obtained by invoking a transform function on each element of the input sequence.
    decimal totalSals = staff.Sum(member => member.salary);
    Console.WriteLine("Total of salaries is {0:c}.", totalSals); // £137,500.00


Take

Returns a specified number of contiguous elements from the start of a sequence.

The Take<TSource> and Skip<TSource> methods are functional complements.
    IEnumerable<int> top3nos = nos.OrderByDescending(x => x).Take(3);
    Console.WriteLine("Top 3 numbers are:");
    foreach (int item in top3nos) {
        Console.Write("{0} ", item);        // 50, 40, 40
    }
    Console.WriteLine();

    IEnumerable<int> top3sal = staff
        .OrderByDescending(member => member.salary)
        .Select(x => x.salary)
        .Take(3);

    Console.WriteLine("Top 3 salaries are:");
    foreach (var item in top3sal) {
        Console.Write("{0:C0} ", item);        // £28,000 £27,000 £22,500
    }


TakeWhile

Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements.

The TakeWhile and SkipWhile methods are functional complements.

TakeWhile 1: Returns elements from a sequence as long as a specified condition is true.
    IEnumerable<string> untilBungle = rainbow.TakeWhile(
        bow => String.Compare("Bungle", bow, true) != 0);
        // true means ignoreCase
    foreach (string bow in untilBungle) {
        Console.WriteLine(bow);
    }       // Rod, Jane, Freddy


TakeWhile 2: Returns elements from a sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function.
    IEnumerable<string> whileLonger = rainbow.TakeWhile((bow, index) =>
        bow.Length > index * index);
    foreach (string item in whileLonger) {
        Console.WriteLine(item);
    }
    // Rod, Jane, Freddy because len(Bungle) is 6, which is <= 3 x 3


ThenBy and ThenByDescending

Perform a subsequent ordering of the elements in a sequence in ascending/descending order. (See OrderBy and OrderByDescending.)

ThenBy/Descending 1: Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.
    IEnumerable<string> bowOrdering = rainbow
        .OrderBy(member => member.Length)
        .ThenBy(member => member);
    foreach (string member in bowOrdering) {
        Console.WriteLine(member);
    }


ThenBy/Descending 2: Performs a subsequent ordering of the elements in a sequence in ascending order by using a specified comparer. Refer to OrderBy and OrderByDescending.

ToArray

Creates an array from an IEnumerable<T>.

The ToArray<TSource>(IEnumerable<TSource>) method forces immediate query evaluation and returns an array that contains the query results. You can append this method to your query in order to obtain a cached copy of the query results.
    string[] staffMembers = staff.Select(member => member.name).ToArray();
    foreach (string member in staffMembers) {
        Console.WriteLine(member);
    }       // Bob Bones, Mary Muggins, etc..


ToDictionary

Creates a Dictionary<TKey, TValue> from an IEnumerable<T>.

There are four overloads of this method. I am following the Microsoft documentation in only providing examples for the first of these. (It is probably rare that you might need the other versions.)

ToDictionary 1: Creates a Dictionary<TKey, TValue> from an IEnumerable<T> according to a specified key selector function.
    var staffDict = staff.ToDictionary(member => member.name);
    foreach (var entry in staffDict) {
        Console.WriteLine("Key: {0} Salary {1:C0}", entry.Key, entry.Value.salary);
    }

    var staffInitials = staff.ToDictionary(member => 
        member.name.Split(' ')[0][0] + member.name.Split(' ')[1][0]);
    foreach (var entry in staffInitials) {
        Console.WriteLine("Key: {0} Salary {1:C0}", entry.Key, entry.Value.salary);
    }
    // Bob Bones yields the key 132, which is 66 x 2, where 66 is the ascii 
    // code for the letter 'B'.


ToDictionary 2: Creates a Dictionary<TKey, TValue> from an IEnumerable<T> according to a specified key selector function and key comparer.

ToDictionary 3: Creates a Dictionary<TKey, TValue> from an IEnumerable<T> according to specified key selector and element selector functions.

ToDictionary 4: Creates a Dictionary<TKey, TValue> from an IEnumerable<T> according to a specified key selector function, a comparer, and an element selector function.

ToList

Creates a List<T> from an IEnumerable<T>.
    List<int> rainbowLens = rainbow.Select(name => name.Length).ToList();
    foreach (int lens in rainbowLens) {
        Console.Write("{0} ", lens);
    }       // 3 4 6 6 5 6

    List<int> salaries = staff.Select(member => member.salary).ToList();
    foreach (int sal in salaries) {
        Console.Write("{0:C0} ", sal);
    }


ToLookup

Creates a generic Lookup<TKey, TElement> from an IEnumerable<T>.

There are four overloads of this method. I haven't repeated the examples here as I would only be copying those from the documentation. the docs. See also Lookup<TKey, TElement> Class.

ToLookup 1: Creates a Lookup<TKey, TElement> from an IEnumerable<T> according to a specified key selector function.
This method returns a Lookup<TKey, TElement>, a one-to-many dictionary that maps keys to collections of values. A Lookup<TKey, TElement> differs from a Dictionary<TKey, TValue>, which performs a one-to-one mapping of keys to single values.

ToLookup 2: Creates a Lookup<TKey, TElement> from an IEnumerable<T> according to a specified key selector function and key comparer.

ToLookup 3: Creates a Lookup<TKey, TElement> from an IEnumerable<T> according to specified key selector and element selector functions.

ToLookup 4: Creates a Lookup<TKey, TElement> from an IEnumerable<T> according to a specified key selector function, a comparer and an element selector function.

See Part 3 for examples of the use of a comparer, although not for this particular method.

Union (see also Intersect)

Produces the set union of two sequences.

This method excludes duplicates from the return set. This is different behavior to the Concat<TSource> method, which returns all the elements in the input sequences including duplicates.

Union 1: Produces the set union of two sequences by using the default equality comparer.
    IEnumerable<string> united = rainbow.Union(extras);
    foreach (string item in united) {
        Console.WriteLine(item);
    }           // all of rainbow, plus Fred


Union 2: Produces the set union of two sequences by using a specified IEqualityComparer<T>. See Part 3.

Where

Where 1: Filters a sequence of values based on a predicate.
    IEnumerable<string> rainbowLen6 = rainbow.Where(bow => bow.Length == 6);
    foreach (string bow in rainbowLen6) {
        Console.WriteLine(bow);
    }       // Freddy, Bungle, George

    IEnumerable<string> earnGT20k = staff
        .Where(member => member.salary > 20000)
        .Select(member => member.name);
    foreach (string member in earnGT20k) {
        Console.WriteLine(member);
    }
    // Mary M, Liz, Dave and Mary P.


Where 2: Filters a sequence of values based on a predicate. Each element's index is used in the logic of the predicate function.
    IEnumerable<int> nosLTindex = nos.Where((no, index) => no <= index * no);
    foreach (int x in nosLT30) {
        Console.Write("{0} ", x);
    }       // 22 22 21 17 10


Zip

Zip<TFirst, TSecond, TResult> : Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.

The method steps through the two input sequences, applying function resultSelector to corresponding elements of the two sequences. The method returns a sequence of the values that are returned by resultSelector. If the input sequences do not have the same number of elements, the method combines elements until it reaches the end of one of the sequences. For example, if one sequence has three elements and the other one has four, the result sequence has only three elements.

Basically, two collections are iterated, examining elements from each collection as a pair. Some expression is applied to each of these two elements and the result stored in a new collection. If one collection runs out before the other then the process halts.
    IEnumerable<string> nosAndRainbow = nos.Zip(rainbow,
        (first, second) => first + " " + second);
    foreach (string item in nosAndRainbow) {
        Debug.Print(item);
    }
    //34 Rod
    //22 Jane
    //22 Freddy
    //21 Bungle
    //40 Zippy
    //31 George

    IEnumerable<int> nosAndSalary = nos.Zip(staff,
        (first, second) => first + second.salary);
    foreach (int item in nosAndSalary) {
        Console.WriteLine("{0:C0}", item);
    }       // £20,034, £22,022, etc..


Enumerable Methods A-L
Methods Using IEqualityComparer
Query Expression Syntax
LINQ to XML Querying

This post has been edited by andrewsw: 04 September 2014 - 04:12 PM


Is This A Good Question/Topic? 2
  • +

Replies To: LINQ by Example 2: Enumerable Methods M-Z

#2 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Posted 25 August 2014 - 01:25 PM

Just an additional note on Enumerable.Range it isn't range in sense
1 To 10 but start To (start + count) -1
The parameters are Range(start, count)
The count has to be greater than Zero.
  Enumerable.Range(10, 5)  /* {10. 11. 12. 13. 14} */
  Enumerable.Range(1 , 1)  /* {1}                  */


Was This Post Helpful? 1
  • +
  • -

#3 andrewsw  Icon User is online

  • It's just been revoked!
  • member icon

Reputation: 3838
  • View blog
  • Posts: 13,595
  • Joined: 12-December 12

Posted 25 August 2014 - 01:41 PM

Thank you @Adam, I've added a detail to that effect.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1