Full Lectures Set
- C#Lectures - Lecture 1: Primitive Types
- C# Lectures - Lecture 2: Work with text in C#: char, string, StringBuilder, SecureString
- C# Lectures - Lecture 3 Designing Types in C#. Basics You Need to Know About Classes
- C# Lectures - Lecture 4: OOP basics: Abstraction, Encapsulation, Inheritance, Polymorphism by C# example
- C# Lectures - Lecture 5:Events, Delegates, Delegates Chain by C# example
- C# Lectures - Lecture 6: Attributes, Custom attributes in C#
- C# Lectures - Lecture 7: Reflection by C# example
- C# Lectures - Lecture 8: Disaster recovery. Exceptions and error handling by C# example
- C# Lectures - Lecture 9:Lambda expressions
- C# Lectures - Lecture 10: LINQ introduction, LINQ to 0bjects Part 1
- C# Lectures - Lecture 11: LINQ to 0bjects Part 2. Nondeferred Operators
Introduction
This is second article about LINQ to Objects and it is continuation of first article for this topic. Here I'll concentrate on reviewing rest of operators that are available in LINQ and focus on Nondeferred Operators.
Nondeferred Operators
In previous article I reviewed Deferred Operators if you take a look on them, you'll see that all of them return IEnumerable<T> or OrderedSequence<T>. Nondeferred Operators in opposite to Deferred return data types that are not IEnumerable<T> or OrderedSequence<T>.
Let's review all Nondeferred operators available at the moment:
In most examples we will use following data structure on which we will call operators that are reviewed:
string[] CarBrands = { "Mersedes", "Ford", "Lexus", "Toyota",
"Honda", "Hyunday", "BMW", "KIA", "Chevrolet",
"Tesla", "Lamborghini", "Ferrari", "Lincoln",
"Cadillac"};
- ToArray - creates array of the same type as input sequence. Has following prototype:
- public static T[] ToArray<T>(this IEnumerable<T> source); - this function takes an input sequence of type T and transforms it to array of type T.
CODE:
Console.WriteLine("\n-----------------TOARRAY");
List<string> Names = new List<string>();
Names.Add("Sergey");
Names.Add("Alexander");
Names.Add("Maria");
Names.Add("John");
Names.Add("Bruce");
Names.Add("Emily");
Console.WriteLine("Names type = " + Names.GetType().ToString());
var newNames = Names.ToArray();
Console.WriteLine("newNames type = " + newNames.GetType().ToString());
RESULT:
<img alt="" src="1128873/ToArray.PNG" />
- ToList - converts input sequence of type to list of the same type. Has following prototype:
- public static List<T> ToList<T>(this IEnumerable<T> source); - this function takes input sequence of type T and transforms it to list of type T.
CODE:
Console.WriteLine("\n-----------------TOLIST");
Console.WriteLine("CarBrands type = " + CarBrands.GetType().ToString());
var newCarBrands = CarBrands.ToList();
Console.WriteLine("newCarBrands type = " + newCarBrands.GetType().ToString());
RESULT:
<img alt="" src="1128873/ToList.PNG" />
- ToDictionary - converts input sequence of type T to dictionary of type T with key K. There are 4 prototypes here:
- public static Dictionary<K, T> ToDictionary<T, K>(this IEnumerable<T> source,Func<T, K> keySelector); - this function takes input sequence of type T and delegate -keySelector to extract key from each sequence element and use it as key in Dictionary that is returned. Returned Dictionary is of the same type as input sequence. In returned dictionary to compare keys default comparer is used EqualityComparer<K>.Default.
- public static Dictionary<K, T> ToDictionary<T, K>(this IEnumerable<T> source,Func<T, K> keySelector,IEqualityComparer<K> comparer); - this prototype is exact as previous one, but it gives you ability to provide a comparer object that implements IEqualityComparer<K> interface to compare dictionary keys.
- public static Dictionary<K, E> ToDictionary<T, K, E>(this IEnumerable<T> source,Func<T, K> keySelector,Func<T, E> elementSelector); - this prototype is exact as first one, but it gives you ability to provide elementSelector delegate that will transform input element of sequence from type T to type E. Result dictionary will contain elements of type E with keys of type K.
- public static Dictionary<K, E> ToDictionary<T, K, E>(this IEnumerable<T> source,Func<T, K> keySelector,Func<T, E> elementSelector,IEqualityComparer<K> comparer); - fourth prototype is the most wide one. This is combination of second and third options. Here you can implement your own comparer for keys in dictionary and implement elementSelector to convert input sequences elements to different type that will be stored in result dictionary.
CODE:
Console.WriteLine("\n-----------------TODICTIONARY");
Console.WriteLine("-----------------first version");
Dictionary<int, string> outDict = CarBrands.ToDictionary(s => Array.IndexOf(CarBrands, s));
foreach (var element in outDict)
{
Console.WriteLine("Key = " + element.Key + " Value = " + element.Value);
}
Console.WriteLine("-----------------second version");
IntComparer comp = new IntComparer();
outDict = CarBrands.ToDictionary(s => Array.IndexOf(CarBrands, s),comp);
foreach (var element in outDict)
{
Console.WriteLine("Key = " + element.Key + " Value = " + element.Value);
}
Console.WriteLine("-----------------third version");
Dictionary<int, int> dict = CarBrands.ToDictionary(s => Array.IndexOf(CarBrands, s),el => el.Length);
foreach (var element in dict)
{
Console.WriteLine("Key = " + element.Key + " Value = " + element.Value);
}
Console.WriteLine("-----------------fourth version");
dict = CarBrands.ToDictionary(s => Array.IndexOf(CarBrands, s), el => el.Length,comp);
foreach (var element in dict)
{
Console.WriteLine("Key = " + element.Key + " Value = " + element.Value);
RESULT:
<img alt="" src="1128873/ToDictionary_1.PNG" />
<img alt="" src="1128873/ToDictionary_2.PNG" />
- ToLookup - creates a lookup from input sequence. Has 4 prototypes as well:
- public static ILookup<K, T> ToLookup<T, K>(this IEnumerable<T> source,Func<T, K> keySelector); - this function takes input sequence of type T and delegate -keySelector to extract key from each sequence element and use it as key in Lookup that is returned. Returned Dictionary is of the same type as input sequence. In returned dictionary to compare keys default comparer is used EqualityComparer<K>.Default.
- public static ILookup<K, T> ToLookup<T, K>(this IEnumerable<T> source,Func<T, K> keySelector,IEqualityComparer<K> comparer); - this prototype is exact as previous one, but it gives you ability to provide a comparer object that implements IEqualityComparer<K> interface to compare lookup keys.
- public static ILookup<K, E> ToLookup<T, K, E>(this IEnumerable<T> source,Func<T, K> keySelector,Func<T, E> elementSelector); - this prototype is exact as first one, but it gives you ability to provide elementSelector delegate that will transform input element of sequence from type T to type E. Result lookup will contain elements of type E with keys of type K.
- public static ILookup<K, E> ToLookup<T, K, E>(this IEnumerable<T> source,Func<T, K> keySelector,Func<T, E> elementSelector,IEqualityComparer<K> comparer); - fourth prototype is the most wide one. This is combination of second and third options. Here you can implement your own comparer for keys in lookup and implement elementSelector to convert input sequences elements to different type that will be stored in result lookup.
CODE:
Console.WriteLine("\n-----------------TOLOOKUP");
Console.WriteLine("-----------------first version");
ILookup<int, string> outLook = CarBrands.ToLookup(s => Array.IndexOf(CarBrands, s));
IEnumerable<string> car = outLook[4];
foreach (var str in car)
{
Console.WriteLine("Fifth car is = " + str);
}
Console.WriteLine("-----------------second version");
outLook = CarBrands.ToLookup(s => Array.IndexOf(CarBrands, s),comp);
car = outLook[3];
foreach (var str in car)
{
Console.WriteLine("Fourth car is = " + str);
}
Console.WriteLine("-----------------third version");
ILookup<int, int> outLook2 = CarBrands.ToLookup(s => Array.IndexOf(CarBrands, s),el => el.Length);
IEnumerable<int> carl = outLook2[4];
foreach (var i in carl)
{
Console.WriteLine("Fifth car lengh is = " + i);
}
Console.WriteLine("-----------------fourth version");
outLook2 = CarBrands.ToLookup(s => Array.IndexOf(CarBrands, s), el => el.Length,comp);
carl = outLook2[3];
foreach (var i in carl)
{
Console.WriteLine("Fourth car lengh is = " + i);
}
RESULT:
<img alt="" src="1128873/ToLookup.PNG" />
- SequenceEqual - this operator determines if two input sequences are equal. Has two prototypes:
- public static bool SequenceEqual<T>(this IEnumerable<T> first,IEnumerable<T> second); - this function compares all elements of input sequences using System.Object.Equals method. If all elements are equal it returns true.
- public static bool SequenceEqual<T>(this IEnumerable<T> first,IEnumerable<T> second,IEqualityComparer<T> comparer); - this function is the same as the first one, but it allows you to define your own comparer for sequences elements.
CODE:
Console.WriteLine("\n-----------------SEQUENCEEQUAL");
Console.WriteLine("-----------------first version");
int[] seq1 = { 0, 5, 25 };
int[] seq2 = { 0, 5, 25 };
string[] Cars2 = { "Ford", "Acura"};
Console.WriteLine(CarBrands.SequenceEqual(Cars2));Console.WriteLine(seq1.SequenceEqual(seq2));Console.WriteLine("-----------------second version");
Console.WriteLine(seq1.SequenceEqual(seq2,comp));
RESULT:
<img alt="" src="1128873/SequenceEqual.PNG" />
- First - returns first element of the sequence or the one that matches input predicate. If you call it on empty sequence it will raise exception System.InvalidOperationException. Has two prototypes:
- public static T First<T>(this IEnumerable<T> source); - simply returns first element of the sequence
- public static T First<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns first element from sequence that matches predicate
CODE:
Console.WriteLine("\n-----------------FIRST");
Console.WriteLine("-----------------first version");
Console.WriteLine(CarBrands.First());Console.WriteLine("-----------------second version");
Console.WriteLine(CarBrands.First(s=>s.StartsWith("BM")));
RESULT:
<img alt="" src="1128873/First.PNG" />
- FirstOrDefault - returns first element of the sequence or the one that matches input predicate. It is similar to the First operator but if the sequence is empty it returns default(T). As you remember for all reference type default value is null. Has two prototypes:
- public static T FirstOrDefault<T>(this IEnumerable<T> source); - simply returns first element of the sequence
- public static T FirstOrDefault<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns first element from sequence that matches predicate
CODE:
Console.WriteLine("\n-----------------FIRSTORDEFAULT");
Console.WriteLine("-----------------first version");
Console.WriteLine(CarBrands.FirstOrDefault());string [] seqstr = {};
try
{
Console.WriteLine(seqstr.First());
}
catch (System.InvalidOperationException e)
{
Console.WriteLine("Fisrt operator on empty sequence raises exception");
}
if(String.IsNullOrEmpty(seqstr.FirstOrDefault()))
{
Console.WriteLine("We got default value of string = null");
}
Console.WriteLine("-----------------second version");
Console.WriteLine(CarBrands.FirstOrDefault(s => s.StartsWith("BM")));
RESULT:
<img alt="" src="1128873/FirstOrDefault.PNG" />
- Last - returns last element of the sequence or the one that matches input predicate. If you call it on empty sequence it will raise exception System.InvalidOperationException. Has two prototypes:
- public static T Last<T>(this IEnumerable<T> source); - simply returns first element of the sequence
- public static T Last<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns first element from sequence that matches predicate
CODE:
Console.WriteLine("\n-----------------LAST");
Console.WriteLine("-----------------first version");
Console.WriteLine(CarBrands.Last());Console.WriteLine("-----------------second version");
Console.WriteLine(CarBrands.Last(s => s.StartsWith("L")));
RESULT:
<img alt="" src="1128873/Last.PNG" />
- LastOrDefault - returns last element of the sequence or the one that matches input predicate. It is similar to the Last operator but if the sequence is empty it returns default(T). As you remember for all reference type default value is null. Has two prototypes:
- public static T LastOrDefault<T>(this IEnumerable<T> source); - simply returns last element of the sequence
- public static T LastOrDefault<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns last element from sequence that matches predicate
CODE:
Console.WriteLine("\n-----------------LASTORDEFAULT");
Console.WriteLine("-----------------first version");
Console.WriteLine(CarBrands.LastOrDefault());try
{
Console.WriteLine(seqstr.Last());
}
catch (System.InvalidOperationException e)
{
Console.WriteLine("Last operator on empty sequence raises exception");
}
if (String.IsNullOrEmpty(seqstr.LastOrDefault()))
{
Console.WriteLine("We got default value of string = null");
}
Console.WriteLine("-----------------second version");
Console.WriteLine(CarBrands.LastOrDefault(s => s.StartsWith("L")));
RESULT:
<img alt="" src="1128873/LastOrDefault.PNG" />
- Single - returns the single element of input sequence that contains only one element or returns single element from. Has two prototypes:
- public static T Single<T>(this IEnumerable<T> source); - simply returns last element of the sequence
- public static T Single<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns last element from sequence that matches predicate
CODE:
Console.WriteLine("\n-----------------SINGLE");
Console.WriteLine("-----------------first version");
string[] singleElementSequence = { "single one"};
Console.WriteLine(singleElementSequence.Single());Console.WriteLine("-----------------second version");
Console.WriteLine(CarBrands.Single(s => s.StartsWith("Lin")));
RESULT:
<img alt="" src="1128873/Single.PNG" />
- SingleOrDefault - similar to previous operator it returns the single element of input sequence that contains only one element or returns single element from. The only difference is the way how it behaves when search element is not found, in this case it returns default(T). Has two prototypes:
- public static T SingleOrDefault<T>(this IEnumerable<T> source); - simply returns last element of the sequence
- public static T SingleOrDefault<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns last element from sequence that matches predicate
CODE:
Console.WriteLine("\n-----------------SINGLEORDEFAULT");
Console.WriteLine("-----------------first version");
string[] singleElementSequence2 = {};
if (String.IsNullOrEmpty(singleElementSequence2.SingleOrDefault()))
{
Console.WriteLine("We got default value of string = null");
}
Console.WriteLine("-----------------second version");
if (String.IsNullOrEmpty(singleElementSequence2.SingleOrDefault(s=> s.StartsWith("strange string"))))
{
Console.WriteLine("We again got default value of string = null");
}
RESULT:
<img alt="" src="1128873/SingleOrDefault.PNG" />
- ElementAt - returns the element of the source from specific position in sequence. Has two prototypes:
- public static T ElementAt<T>(this IEnumerable<T> source,int index); - takes input index and return element on that position
CODE:
Console.WriteLine("\n-----------------ELEMENTAT");
Console.WriteLine("Element at position 2 is: " + CarBrands.ElementAt(2));
RESULT:
<img alt="" src="1128873/ElementAt.PNG" />
- - similar to previous operator it returns the element from specific index of input sequence or returns single element from. The only difference is the way how it behaves when input index is wrong or input sequence is null, in this case it returns default(T). Has one prototypes:
- public static T ElementAtOrDefault<T>(this IEnumerable<T> source,int index); - simply returns last element of the sequence
CODE:
Console.WriteLine("\n-----------------ELEMENTATORDEFAULT");
if (String.IsNullOrEmpty(CarBrands.ElementAtOrDefault(-1)))
{
Console.WriteLine("We got default value of string = null");
}
RESULT:
<img alt="" src="1128873/ElementAtOrDefault.PNG" />
- Any - returns true if any element of the input sequence matches condition. Has two prototypes:
- public static bool Any<T>(this IEnumerable<T> source); - this function returns true if at least any element present in sequence
- public static bool Any<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns true if at least one element of input sequence causes predicate tor return true
CODE:
Console.WriteLine("\n-----------------ANY");
Console.WriteLine("-----------------first version");
string[] emptySequence = { };
if (!emptySequence.Any())
{
Console.WriteLine("Input sequence is empty");
}
Console.WriteLine("Has CarBrands any elements? : " + CarBrands.Any());
Console.WriteLine("-----------------second version");
Console.WriteLine("Does car brands has something that starts with B: " + CarBrands.Any(s=> s.StartsWith("B")));
RESULT:
<img alt="" src="1128873/Any.PNG" />
- All - returns true if all elements of the input sequence matches condition. Has following prototype:
- public static bool All<T>(this IEnumerable<T> source,Func<T, bool> predicate); - returns true if all elements of input sequence cause predicate tor return true
CODE:
Console.WriteLine("\n-----------------ALL");
Console.WriteLine("Do all elements of CarBrands has more than 3 symbols: " + CarBrands.All(s => {if(s.Length>3)return true;return false;}));
Console.WriteLine("Do all elements of CarBrands has more than 2 symbols: " + CarBrands.All(s => { if (s.Length > 2)return true; return false; }));
RESULT:
<img alt="" src="1128873/All.PNG" />
- Contains - returns true if any of the elements in input sequence contains input value. Has following prototypes:
- public static bool Contains<T>(this IEnumerable<T> source,T value); - returns true if any of the elements of input sequence matches input value
- public static bool Contains<T>(this IEnumerable<T> source,T value, IEqualityComparer<T> comparer); - same as previous version but with ability to define your own comparer
CODE:
Console.WriteLine("\n-----------------Contains");
Console.WriteLine("-----------------first version");
Console.WriteLine("Does CarBrands contain BMW: " + CarBrands.Contains("BMW"));
int[] ints = { 0, 1, 2, 3, 4, 5 };
Console.WriteLine("-----------------second version");
Console.WriteLine("Does ints contain 5 with comparer: " + ints.Contains(5,comp));
RESULT:
<img alt="" src="1128873/Contains.PNG" />
- Count - returns number of elements in input sequence:
- public static int Count<T>(this IEnumerable<T> source);
- public static int Count<T>(this IEnumerable<T> source,Func<T, bool> predicate); - if first prototype is pretty straightforward, then second is very interesting. It returns count of elements in input sequence that match specific predicate condition. This function I treat as one of the most convenient and useful in real life programming as it simplifies your life a lot.
CODE:
Console.WriteLine("\n-----------------Count");
Console.WriteLine("-----------------first version");
Console.WriteLine("CarBrands count: " + CarBrands.Count());
Console.WriteLine("-----------------second version");
Console.WriteLine("CarBrands count where length > 4: " + CarBrands.Count(s=> s.Length > 4));
RESULT:
<img alt="" src="1128873/Count.PNG" />
- LongCount - returns number of elements in input sequence as long. Similar to count and also has two prototypes:
- public static long LongCount<T>(this IEnumerable<T> source);
- public static long LongCount<T>(this IEnumerable<T> source,Func<T, bool> predicate);
CODE:
Console.WriteLine("\n-----------------LongCount");
Console.WriteLine("-----------------first version");
Console.WriteLine("CarBrands count: " + CarBrands.LongCount());
Console.WriteLine("-----------------second version");
Console.WriteLine("CarBrands count where length > 5: " + CarBrands.LongCount(s => s.Length > 5));
RESULT:
<img alt="" src="1128873/LongCount.PNG" />
- Sum - returns sum of elements of input sequence that contains numeric values: int, long, double or decimal. Has following prototypes:
- public static Numeric Sum(this IEnumerable<Numeric> source);
- public static Numeric Sum<T>(this IEnumerable<T> source,Func<T, Numeric> selector); - this function gives you ability to implement selector delegate that select only values you want and in this case you can call it on a sequence that is not Numeric
CODE:
Console.WriteLine("\n-----------------Sum");
double[] doubles = { 0.1, 1.2, 2.3, 3.5, 4.6, 5.3 };
Console.WriteLine("-----------------first version");
Console.WriteLine("Sum of doubles is: " + doubles.Sum());
Console.WriteLine("-----------------second version");
Console.WriteLine("Sum of chars in CarBrands is: " + CarBrands.Sum(s=> s.Length));
RESULT:
<img alt="" src="1128873/Sum.PNG" />
- Min - returns minimal value from input sequence. Has following prototypes:
- public static Numeric Min(this IEnumerable<Numeric> source); - simplest one for numerical sequences.
- public static T Min<T>(this IEnumerable<T> source); - same as first but for not numerical types
- public static Numeric Min<T>(this IEnumerable<T> source,Func<T, Numeric> selector); - can be called on not numerical sequences but selector should take from that sequence some numerical field.
- public static S Min<T, S>(this IEnumerable<T> source,Func<T, S> selector); - this function is like second but if gives you ability to use selector delegate
CODE:
Console.WriteLine("\n-----------------Min");
Console.WriteLine("-----------------first version");
Console.WriteLine("Min of doubles is: " + doubles.Min());
Console.WriteLine("-----------------second version");
Console.WriteLine("Min in CarBrands: " + CarBrands.Min());
Console.WriteLine("-----------------third version");
Console.WriteLine("Min in CarBrands by length is: " + CarBrands.Min(s => s.Length));
Console.WriteLine("-----------------fourth version");
Console.WriteLine("Min in CarBrands (we imagine this is class and return string value for name from it) : " + CarBrands.Min(s => s.ToString()));
RESULT:
<img alt="" src="1128873/Min.PNG" />
- Max - returns maximal value from input sequence. Has following prototypes:
- public static Numeric Max(this IEnumerable<Numeric> source); - simplest one for numerical sequences.
- public static T Max<T>(this IEnumerable<T> source); - same as first but for not numerical types
- public static Numeric Max<T>(this IEnumerable<T> source,Func<T, Numeric> selector); - can be called on not numerical sequences but selector should take from that sequence some numerical field.
- public static S Max<T, S>(this IEnumerable<T> source,Func<T, S> selector); - this function is like second but if gives you ability to use selector delegate
CODE:
Console.WriteLine("\n-----------------Max");
Console.WriteLine("-----------------first version");
Console.WriteLine("Mxn of doubles is: " + doubles.Max());
Console.WriteLine("-----------------second version");
Console.WriteLine("Max in CarBrands: " + CarBrands.Max());
Console.WriteLine("-----------------third version");
Console.WriteLine("Max in CarBrands by length is: " + CarBrands.Max(s => s.Length));
Console.WriteLine("-----------------fourth version");
Console.WriteLine("Max in CarBrands (we imagine this is class and return string value for name from it) : " + CarBrands.Max(s => s.ToString()));
RESULT:
<img alt="" src="1128873/Max.PNG" />
- Average - returns average of elements of input sequence that contains numeric values: int, long, double or decimal. Has following prototypes:
- public static Numeric Average(this IEnumerable<Numeric> source);
- public static Numeric Average<T>(this IEnumerable<T> source,Func<T, Numeric> selector); - this function gives you ability to implement selector delegate that select only values you want and in this case you can call it on a sequence that is not Numeric
CODE:
Console.WriteLine("\n-----------------Average");
Console.WriteLine("-----------------first version");
Console.WriteLine("Average of doubles is: " + doubles.Average());
Console.WriteLine("-----------------second version");
Console.WriteLine("Average of lengths in CarBrands is: " + CarBrands.Average(s => s.Length));
RESULT:
<img alt="" src="1128873/Average.PNG" />
Conclusions
You should be very careful when using nondeffered operators. Most of the work well in such called "good" way. Once you put wrong input to it or operator can't handle data properly it will raise exception. Before you decide to use some operator open its documentation and make sure you're aware about extreme cases and the way it handles problematic situations and which exceptions or return values are generated in those cases.
Sources
- Pro LINQ Language Integrated Query in C# 2010 Adam Freeman and Joseph C. Rattz, Jr.
- https://msdn.microsoft.com
- http://www.codeproject.com/Articles