9. LINQ Operators || C# 10 Flashcards
What are the standart query operators categories?
Give an example of each
- Sequence in, sequence out (sequence -> sequence)
Where<>
,OrderBy<>
,ToList<>
and others.. - Sequence in, single element or scalar value out
First<>
,Count
,Contains<>
- Nothing in, sequence out (generation methods)
Empty
,Range
,Repeat
Explain:
Where<>
clause
Where
returns the elements from the input sequence that satisfy the given predicate:IEnumerable<string> query = names.Where(name => name.EndsWith("y"));
A Where<>
clause can appear more than once in a query and be interspersed with let
, orderby
and join
clauses.
What would be equivalent to SQL’s LIKE '%abc%'
? What other SQL command this method could substitute?
c.Name.Contains(“abc”). It can also act like IN
operator in SQL - checking if element is in the table.
Explain the difference between:
Take()
and Skip()
clauses
Take()
emits the first n
elements and discards the rest;Skip()
discards the first n
elements and emits the rest. So its opposite.
~~~
IQueryable<Book> query = dbContext.Books
.Where(b => b.Title.Contains("mercury"))
.OrderBy(b => b.Title).Skip(20).Take(20);
~~~</Book>
Explain the difference between:
-
Take(5..)
andSkip(5)
-
Take(..^5)
andSkipLast(5)
;
The meaning are equal in each row.
* Take(5..)
== Skip(5)
* Take(..^5)
== SkipLast(5)
Explain the difference between:
Distinct()
and DistinctBy<>
Distinct()
will return distinct elements in the given sequence;DistinctBy<>
will also return disctinct elements in a sequence but before apply the given logical operations. The returned results will be after the additional operation application such as:new[] {1.0, 1.1, 2.0, 2.1, 3.0, 3.1}.DistincBy(n => Math.Round(n, 0));
The first step will be to apply the logical operation, after which the sequence will look like this:new[] {1, 1, 2, 2, 3, 3}
. Then the Distinct()
method will take place and return only the distinct elements in the sequence. The result will be: 1, 2, 3
Define:
Select<>
clause
With Select
you always get the same number of elements that you started with. Each elements however, can be transformed in any manner by the mabda function:IEnumerable<string> query = FontFamily.Families.Select(s => s.Name);
It does also accept second parameter in lambda expression to enable indexed projection:IEnumerable<string> query = names.Select((s, i) => i + "=" + s);
// {“0=Tom”, “1=Harry”…}
Explain:
Correlated subquery
A subquery is correlated if it references an object in the outer query. In the example below it references ‘d’, the directory beingenumerated:
~~~
string tempPath = Path.GetPath();
DirectoryInfo[] dirs = new DirectoryInfo(tempPath).GetDirectories();
var query = from d in dirs
where (d.Attributes & FileAttributes.System) == 0
select new
{
DirectoryName = d.FullName,
Created = d.CreationTime,
Files = from f in d.GetFiles()
where (f.Attributes & FileAttributes.Hidden) == 0
select new {FileName = f.Name, f.Lenth, }
};
~~~
Explain the difference between:
Select
and SelectMany
Lets say we have a array of people names: string[] names = ["Harry Styles", "Lewis Capaldi", "Beyonce Knowles"];
and we would like to turn this into the array of names where first and last name is two separate items in array.
If we would use select we would take each element, use Split()
, which would return array of elements. We would make array of arrays and then make a double foreach loop to loop through and make something of that:
~~~
IEnumerable<string[]> splittedNames = names.Select(s => s.Split());
foreach(string[] stringArray in splittedNames){
foreach(string stringElement in stringArray){
…..
}
}
~~~
Now with SelectMany
we could do the same with a single line:
~~~
IEnumerable<string> query = names.SelectMany(s => s.Split());
foreach(string name in query){
.....
}
~~~
With `SelectMany` we can expand child sequences, flatten nested collections, and join two collections into a flat output sequence. If we would translate to query syntax `SelectMany` would have two range variables (from n in names...)</string>
What is the SelectMany
equivalent in SQL?
SelectMany
can perform cross-joins, non-equi joins, inner joins and left outer joins
How to include data from child table vs parent table in LINQ?
Child : each from
clause introduces a new child table.
Parent : to include data from a parent table you simply navigate to the property:
from c in dbContext.Customers select new { Name = c.Name, SalesPerson = c.SalesPerson.Name};
SalesPerson.Name is a parent property here
What is Select()
equivalent to in SQL?
Select()
subquery yields a result analogous to a left outer join: every outer element is included, regardless of whether it has any of other parameters
How we can turn left outer join to the inner join but written in LINQ?
We should replace Select()
(left outer join) with SelectMany()
: in the process of flattening the query we will switch to an inner join: customers are included only for whom one or more high-value purchases exist:
from c in dbContext.Customers from p in c.Purchaces where p.Price > 1000 select new { c.Name, p.Description, p.Price };
What is SQL equivalent of Join()
? How does this method work?
INNER JOIN
Applies a lookup strategy to match elements from two collections, emitting a flat result set
We can use both SelectMany()
and Join()
to inner join the elements with matching keys. Which is better over other?
Although both queries yield the same results, the Join()
query is considerably faster because its implementation in Enumerable preloads the inner collection (purchase) into a keyed lookup
Let’s say we have this block of code:
~~~
from c in customers
select new
{
CustName = c.Name,
custPurchases = purchases.Where(w => c.ID == w.CustomerId)
};
~~~
What would be a more efficient way of writting the same thing?
More efficient way would be to use GroupJoin
like this:
~~~
from c in customers
join p in purchases ob c.ID equals p.CustomerID
into customerPurchases
select new {CustNames = c.Name, custPurchases };
~~~
By doing this the left outer join is performed by default. This means that if the customer does not have a purchase - it wont be excluded. To do that we need to do an inner join
Explain
“lookup” in LINQ queries?
A “lookup” is a sequence of groupings that can be accessed directly by key. Another way to think of it is as a dictionary of sequences - a dictionary that can accept many elements under eah key (sometimes called a multidictionary)
~~~
public interface ILookup<TKey, TElement> : IEnumerable<IGrouping<TKey, TElement», IEnumerable
{
int Count {get; set;}
bool Contains {get; set;}
IEnumerable<TElement> this [TKey key] {get; }
}
~~~</TElement>
Explain what it is and how it works:
Zip
operator
IEnumerable<TFirst>, IEnumerable<TSecond>=> IEnumerable<TResult>
The Zip
operator enumerates two sequences in step, returning a sequence based on applying a function over each element pair :
~~~
int[] numbers = {3, 5, 7};
string[] words = {“three”, “five”, “seven”, “ignored”};
IEnumerable<string> zip = numbers.Zip(words, (n, w) => n + "=" + w);
~~~
zip == "3=three", "5=five", 7="seven"</string>
What is the difference between Concat
and Union
operators?
Concat returns all the elements of the first sequence, followed by all the elements of the second.
Union does the same but removes any duplicates
What is the difference between Intersect
and Except
operators?
Intersect returns the elements that two sequences have in common.
Except returns the elements in the first input sequence that are not present in the second
Explain how OfType
is different from Cast
operator
OfType and Cast accept non-generic IEnumerable collection and emit a generic IEnumerable<T> sequence that you can subsequently query.
Cast and OfType differ in their behaviour when encountering an input element that’s of an incompatible type. Cast throws an exception; OfType ignores the incompatible element.</T>
What is the difference between FirstOrDefault
and SingleOrDefault
operators if they both return just one element?
First
and FirstOrDefault
returns the first element in the sequence, optionally satisfying a predicate;Single
and SingleOrDefault
are equivalent to First
/ FirstOrDefault
, but throws and exception if there is more than one match
What would be returned by these methods?
int[] numbers = { 1, 2, 3, 4, 5 };
1) numbers.FirstOrDefault(f => f % 2 == 0);
2) numbers.SingleOrDefault(f => f % 2 == 0);
FirstOrDefault
will return ‘2’ as result;SingleOrDefault
will throw an exception because there are more than one element that fits the expression. To prevent the exception, Single
requires exactly one matching element; SingleOrDefault
requires one or zero matching elements;
Where Single
operator is used if First
can do the same thing?
In EF Core, Single
is often used to retrieve a row from a table by primary key (since there can’t be multiple results here);
What are the differences between Max
and MaxBy
(Min
/ MinBy
) operators?
MinBy
and MaxBy
operators return the elements with the smallest or largest value, as determined by a keySelector
. Min
/ Max
operators return the smallest or biggest value itself:
~~~
string[] names = {“Tom”, “Richard”, “Harry”, “Marry”, “Jay”};
names.MinBy(m => m.Length);
names.Min(min => min.Length);
~~~
MinBy result : Tom
Min result : 3
When a selector expression in manadatory in Aggregation methods like Min
, Max
, etc.?
A selector expression is mandatory if the items themselves are not intrisically comparable - in other words, if they do not implement IComparable<T>
:
~~~
Purchase runtimeError = dbContext.Purchase.Min();
decimal? lowestPrice = dbContext.Purchase.Min(m => m.Price);
~~~
What does it mean for Agregate
method to be seeded or unseeded?
Agregate
method can be supplied with 3 parameters:
1. First parameter is the seed, from which the accumulation starts.
2. Second argument is an expression to update the accumulated value, given a fresh element..
3. Third argument can be given to project the final result value from the accumulated value;
~~~
int[] numbers = {1, 2, 3};
int sum = numbers.Agregate(0, (total, n) => total + n);
~~~
If we omit the seed value when calling Agregate
in which case the first element becomes the implicit seed, and aggregation proceeds from the second element. Here’s an unseeded example :
~~~
int[] numbers = {1, 2, 3};
int sum = numbers.Agregate((total, n) => total + n);
~~~
Although both seeded and unseeded examples return the same result “6”, but the calculations are acctually different:
seeded: 0+1+2+3 = 6
unseeded: 1+2+3 = 6
What are the main way to use unseeded aggregations. Give example why
The unseeded aggregation methods are intended for use with delegates that are commutative and associative. If used otherwise, the result is either unintuitive or nondeterministic. Consider the following function:(total, n) => total + n * n
This neither commutative nor associative.
~~~
int[] numbers = {1, 2, 3};
int sum = numbers.Aggregate((total, n) => total + n*n);
~~~
Instead of calculating this as 2*2 + 3*3 + 4*4
// 29
It calculates:2 + 3*3 + 4*4
// 27
How does .Range()
operator work?
Range accepts a starting index and count (both ints):
~~~
foreach (int i in Enumerable.Range(5, 3))
Console.WriteLine(i + “ ”);
``` // 5 6 7
How does the .Repeat()
operator work?
Repeat accepts an element to repeat and the of repetitions:
~~~
foreach (bool x in Enumerable.Repeat(true, 3))
Console.Write(x + “ ”);
``` // true true true