LINQ Query, Selection, Partial Selections and Aggregations
Let’s review a bunch of small functions that show you a few LINQ operations.
The example below shows you how to use the Where and Select LINQ extensions:
public static void LinqQueryAndSelection() { List<string> fruits = new List<string> { "apple", "passionfruit", "banana", "mango", "orange", "blueberry", "grape", "strawberry" }; // find all fruits that have names of length 5 or less IEnumerable<string> query1 = fruits.Where(fruit => fruit.Length < 6); foreach (string fruit in query1) Console.WriteLine(fruit); // convert the names of all the fruits to uppercase IEnumerable<string> query2 = fruits.Select(n => n.ToUpper()); foreach (string fruit in query2) Console.WriteLine(fruit); }
This next example shows you how to do partial selections:
public static void LinqPartialSelection() { List<string> fruits = new List<string> { "apple", "passionfruit", "banana", "mango", "orange", "blueberry", "grape", "strawberry" }; // find first 3 fruits IEnumerable<string> query1 = fruits.Take(3); foreach (string fruit in query1) Console.WriteLine(fruit); // skip the first 3 fruits IEnumerable<string> query2 = fruits.Skip(3); foreach (string fruit in query2) Console.WriteLine(fruit); // single element operations string firstFruit = fruits.First(); // apple string lastFruit = fruits.Last(); // strawberry string thirdFruit = fruits.ElementAt(2); // banana string fruitStratingWithM = fruits.First(f => f.StartsWith("m")); // mango }
This last example shows you how to use LINQ to aggregate values:
public static void LinqAggregation() { int[] numbers = { 3, 4, 5, 6, 7, 8 }; // aggregation operations int count = numbers.Count(); // 6 int min = numbers.Min(); // 3 int max = numbers.Max(); // 8 double average = numbers.Average(); // 5.5 // the operators above also take an optional predicate int countEvensOnly = numbers.Count(n => n % 2 == 0); // assume that values decay over period // MAX and MIN functions allow the numbers to be transformed // before the operation int maxAfterMultiplicationByTwo = numbers.Max(n => n * 2); // 16 }
There is much more to LINQ than these starter examples. From an interviewing perspective you should learn in depth about the standard Query operations which can be broken down into several categories:
- Filtering operations: Where, Take, Skip, etc.
- Project operations: Select, Join, etc.
- Ordering operations: OrderBy, ThenBy, Reverse. etc.
- Grouping operations: GroupBy
- Set operations: Concat, Union, etc.
- Element operations: First, FirstOrDefault, Last, etc.
- Aggregation operations: Count, Min, Max, Sum, etc.
- Qualifier operations: Contains, Any, All, etc.
- Conversion operations: ToArray, ToList, Cast, etc.
Another important fact to note is that LINQ operations can be chained as shown in the example below.
public static void LinqChaining() { List<string> fruits = new List<string> { "apple", "passionfruit", "banana", "mango", "orange", "blueberry", "grape", "strawberry" }; // operator chaining IEnumerable<string> query1 = fruits .Where(f => f.Contains("a")) .OrderBy(f => f.Length) .Select(f => f.ToUpper()); foreach (string fruit in query1) Console.WriteLine(fruit); }
--------------------%%%%%%%-----------------------------------------------------------------------------------
Question: Given an array of numbers, find if ALL numbers are a multiple of a provided number. For example, all of the following numbers - 30, 27, 15, 90, 99, 42, 75 are multiples of 3.
The trick here is to use the Enumerable.All<TSource> method which determines whether all elements of a sequence satisfy a condition.
static void Main(string[] args) { int[] numbers = { 30, 27, 15, 90, 99, 42, 75 }; bool isMultiple = MultipleTester(numbers, 3); } private static bool MultipleTester(int[] numbers, int divisor) { bool isMultiple = numbers.All(number => number % divisor == 0); return isMultiple; }
Question: Given an array of numbers, find if ANY of the number is divisible by 5. For example, one of the following numbers - 30, 27, 18, 92, 99, 42, 72 is divisible by 5.
Again, the key fact here is to use Enumerable.Any<TSource> method which determines whether any element of a sequence satisfies a condition. The code is very similar to the ALL case.
static void Main(string[] args) { int[] numbers = { 30, 27, 18, 92, 99, 42, 72 }; bool isDivisible = IsDivisible(numbers, 3); } private static bool IsDivisible(int[] numbers, int divisor) { bool isDivisible = numbers.Any(number => number % divisor == 0); return isDivisible; }
Another way to present a similar question that utilizes Enumerable.Any<TSource> method is shown below.
Question: Given a GPSManufacturer and GPSDevice data structure as defined below, find all the manufacturers that have at least 1 or more active GPS devices.
class GpsDevice { public string Name; public bool IsActive; } class GpsManufacturer { public string Name; public GpsDevice[] Devices; } static List<GpsManufacturer> gpsManufacturers = new List<GpsManufacturer> { new GpsManufacturer {Name = "manf1", Devices = new GpsDevice[] { new GpsDevice {Name = "device1", IsActive = true}, new GpsDevice {Name = "device2", IsActive = false} } }, new GpsManufacturer {Name = "manf2", Devices = new GpsDevice[] { new GpsDevice {Name = "device1", IsActive = false}, new GpsDevice {Name = "device2", IsActive = false} } }, new GpsManufacturer {Name = "manf3"} };
The following function finds out the active GPS manufacturers.
public static void ActiveGpsManufacturers() { // Determine which manufacturers have a active device. IEnumerable<string> activeManf = from manf in gpsManufacturers // for all manufacturers where manf.Devices != null && // they have a list of devices // and at least one of the device is active manf.Devices.Any(m => m.IsActive == true) select manf.Name; // select them // just for debugging foreach (string name in activeManf) Console.WriteLine(name); }
As an extension question and using Lambda expressions, consider the following question:
Question: Find the count of all the manufacturers that have at least 1 or more active GPS devices.
public static void ActiveGpsManufacturersCount() { // to count the number of active manufacturers int activeManfCount = gpsManufacturers.Count (manf => (manf.Devices != null && manf.Devices.Any(m => m.IsActive == true))); // debugging Console.WriteLine("Active Manf count: {0}", activeManfCount); }
Question 1: How can you sort a result set based on 2 columns?
Assume that you have 2 tables – Product and Category and you want to sort first by category and then by product name.
Question 2: How can you use LINQ to query against a DataTable?
You cannot query against the
Question 3: LINQ equivalent of foreach for IEnumerable<T>
There is no ForEach extension for IEnumerable; only for List. There is a very good reason for this as explained by Eric Lippert here.
Having said that, there are two ways you can solve this:
Convert the items to list and then do a foreach on it:
Or, alternatively, you can write an extension method of your own.
Question 4: When to use .First and when to use .FirstOrDefault with LINQ?
You should use First when you know or expect the sequence to have at least one element. In other words, when it is an exceptional if the sequence is empty.
Use FirstOrDefault, when you know that you will need to check whether there was an element or not. In other words, when it is legal for the sequence to be empty. You should not rely on exception handling for the check.
Question 5: Write a LINQ expression to concatenate a List<string> in a single string separated by a delimiter.
First of all, it is better to use string.Join to tackle this problem. But for interview purposes, this problem can be approached as follows:
Question 6: Write a LINQ expression to concatenate a List<MyClass> objects in a single string separated by a delimiter. The class provides a specific property (say Name) that contains the string in question.
Question 2: Using LINQ, return a grouped list of products only for categories that have at least one product that is out of stock.
In this case, we run any over a grouping as shown below:
Question 3: Determine if an array of numbers contains all odds.
Question 4: Using LINQ, return a grouped list of products only for categories that have all of their products in stock.
List<Product> products = GetProductList(); var productGroups = from p in products group p by p.Category into g where g.All(p => p.UnitsInStock > 0) select new { Category = g.Key, Products = g };
Assume that you have 2 tables – Product and Category and you want to sort first by category and then by product name.
var sortedProds = _db.Products.Orderby(c => c.Category).ThenBy(n => n.Name)
Question 2: How can you use LINQ to query against a DataTable?
You cannot query against the
DataTable's Rows collection, since DataRowCollection doesn't implement IEnumerable<T>. You need to use the AsEnumerable() extension for DataTable. As an example:var results = from myRow in myDataTable.AsEnumerable() where myRow.Field<int>("RowNo") == 1 select myRow;
Question 3: LINQ equivalent of foreach for IEnumerable<T>
There is no ForEach extension for IEnumerable; only for List. There is a very good reason for this as explained by Eric Lippert here.
Having said that, there are two ways you can solve this:
Convert the items to list and then do a foreach on it:
items.ToList().ForEach(i => i.DoStuff());
Or, alternatively, you can write an extension method of your own.
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action) { foreach(T item in enumeration) { action(item); } }
Question 4: When to use .First and when to use .FirstOrDefault with LINQ?
You should use First when you know or expect the sequence to have at least one element. In other words, when it is an exceptional if the sequence is empty.
Use FirstOrDefault, when you know that you will need to check whether there was an element or not. In other words, when it is legal for the sequence to be empty. You should not rely on exception handling for the check.
Question 5: Write a LINQ expression to concatenate a List<string> in a single string separated by a delimiter.
First of all, it is better to use string.Join to tackle this problem. But for interview purposes, this problem can be approached as follows:
string delimeter = ",";
List<string> items = new List<string>() { "foo", "boo", "john", "doe" };
Console.WriteLine(items.Aggregate((i, j) => i + delimeter + j));
Question 6: Write a LINQ expression to concatenate a List<MyClass> objects in a single string separated by a delimiter. The class provides a specific property (say Name) that contains the string in question.
items.Select(i => i.Name).Aggregate((i, j) => i + delimeter + j)
Question 1: Using LINQ, determine if any word in a list contains the substring “ei”.
string[] words = { "believe", "relief", "receipt", "field" };
bool iAfterE = words.Any(w => w.Contains("ei"));
Console.WriteLine("list has words that contains 'ei': {0}", iAfterE);
Question 2: Using LINQ, return a grouped list of products only for categories that have at least one product that is out of stock.
In this case, we run any over a grouping as shown below:
List<Product> products = GetProductList();
var productGroups =
from p in products
group p by p.Category into g
where g.Any(p => p.UnitsInStock == 0)
select new { Category = g.Key, Products = g };
Question 3: Determine if an array of numbers contains all odds.
int[] numbers = { 1, 11, 3, 19, 41, 65, 19 };
bool onlyOdd = numbers.All(n => n % 2 == 1);
Console.WriteLine("The list contains only odd numbers: {0}", onlyOdd);
Question 4: Using LINQ, return a grouped list of products only for categories that have all of their products in stock.
List<Product> products = GetProductList(); var productGroups = from p in products group p by p.Category into g where g.All(p => p.UnitsInStock > 0) select new { Category = g.Key, Products = g };
What is LINQ?
It
stands for Language Integrated Query. LINQ is collection of standard
query operators that provides the query facilities into .NET framework
language like C# , VB.NET.
|
|||||||||||||||||||||||||||
How LINQ is beneficial than Stored Procedures?
There are couple of advantage of LINQ over stored procedures.
1. Debugging - It is really very hard to debug the Stored procedure but as LINQ is part of .NET, you can use visual studio's debugger to debug the queries. 2. Deployment - With stored procedures, we need to provide an additional script for stored procedures but with LINQ everything gets complied into single DLL hence deployment becomes easy. 3. Type Safety - LINQ is type safe, so queries errors are type checked at compile time. It is really good to encounter an error when compiling rather than runtime exception! |
|||||||||||||||||||||||||||
Why Select clause comes after from clause in LINQ?
The
reason is, LINQ is used with C# or other programming languages, which
requires all the variables to be declared first. From clause of LINQ
query just defines the range or conditions to select records. So that’s
why from clause must appear before Select in LINQ.
|
|||||||||||||||||||||||||||
What is the extension of the file, when LINQ to SQL is used?
The extension of the file is .dbml
|
|||||||||||||||||||||||||||
What is the LINQ file extension that interacts with Code Behind's objects.
its .dbml
|
|||||||||||||||||||||||||||
What is a Lambda expression?
A
Lambda expression is nothing but an Anonymous Function, can contain
expressions and statements. Lambda expressions can be used mostly to
create delegates or expression tree types. Lambda expression uses lambda
operator => and read as 'goes to' operator.
Left side of this operator specifies the input parameters and contains the expression or statement block at the right side. Example: myExp = myExp/10; Now, let see how we can assign the above to a delegate and create an expression tree: delegate int myDel(int intMyNum);
static void Main(string[] args)
{
//assign lambda expression to a delegate:
myDel myDelegate = myExp => myExp / 10;
int intRes = myDelegate(110);
Console.WriteLine("Output {0}", intRes);
Console.ReadLine();
//Create an expression tree type
//This needs System.Linq.Expressions
Expression<myDel> myExpDel = myExp => myExp /10;
}
Why can't datareader by returned from a Web Service's Method.
Cos, it's not realizable.
What is the purpose of SequenceEqual?
The SequenceEqual operator determines whether all elements in two collections are equal and in the same order.
e.g. using System;
using System.Linq;
class Program
{
static void Main()
{
string[] array1 = { "dot", "net", "perls" };
string[] array2 = { "a", "different", "array" };
string[] array3 = { "dot", "net", "perls" };
string[] array4 = { "DOT", "NET", "PERLS" };
bool a = array1.SequenceEqual(array2);
bool b = array1.SequenceEqual(array3);
bool c = array1.SequenceEqual(array4, StringComparer.OrdinalIgnoreCase);
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
}
}
Output
False
True
True
What is the purpose of ElementAt?
The ElementAt operator retrieves the element at a given index in the collection.
e.g. string[] names =
{ "Niladri", "Arina", "Bob","Foo", "Bar" };
Random random = new Random(DateTime.Now.Millisecond);
string name = names.ElementAt(3);
Console.WriteLine("The name chosen is '{0}'.", name);
/*
This code produces the following sample output:
The name chosen at random is 'Foo'.
*/
What is the purpose of SingleOrDefault?
What is the difference between IQueryable and IEnumerable interface?
IEnumerable<T> is applicable
for in-memory data querying, and in contrast IQueryable<T> allows
remote execution, like web service or database querying.
How can we handle concurrency in LINQ?
What is Language Integrated Query (LINQ)?
Write the basic steps to execute a LINQ query.?
|
No comments:
Post a Comment