Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Section 66.40: OrderByDescending

Orders a collection by a specified value.

When the value is an integer, double or float it starts with the maximal value, which means that you get first the positive values, than zero and afterwords the negative values (see Example 1).

When you order by a char the method compares the ascii values of the chars to sort the collection (see Example 2).

When you sort strings the OrderBy method compares them by taking a look at their CultureInfo but normaly starting with the last letter in the alphabet (z,y,x,...).

This kind of order is called descending, if you want it the other way round you need ascending (see OrderBy).

Example 1:

int[] numbers = {-2, -1, 0, 1, 2};

IEnumerable<int> descending = numbers.OrderByDescending(x => x);

// returns {2, 1, 0, -1, -2}

Example 2:

char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z', 'Z'}; IEnumerable<char> descending = letters.OrderByDescending(x => x);

// returns { '{', 'z', 'y', 'b', 'a', '[', 'Z', 'Y', 'B', 'A', '?', '9', '1', '+', '!', ' ' }

Example 3:

class Person

{

public string Name { get; set; } public int Age { get; set; }

}

var people = new[]

{

new Person {Name = "Alice", Age = 25}, new Person {Name = "Bob", Age = 21}, new Person {Name = "Carol", Age = 43}

};

var oldestPerson = people.OrderByDescending(x => x.Age).First(); var name = oldestPerson.Name; // Carol

Section 66.41: Union

Merges two collections to create a distinct collection using the default equality comparer

int[]

numbers1 =

{

1,

2,

3 };

 

 

int[]

numbers2

=

{

2,

3,

4, 5

};

 

var allElement

=

numbers1.Union(numbers2);

// AllElement now contains 1,2,3,4,5

 

 

 

 

 

 

 

 

 

Live Demo on .NET Fiddle

GoalKicker.com – C# Notes for Professionals

382

Section 66.42: GroupJoin with outer range variable

Customer[] customers = Customers.ToArray();

Purchase[] purchases = Purchases.ToArray();

var groupJoinQuery = from c in customers

join p in purchases on c.ID equals p.CustomerID into custPurchases

select new

{

CustName = c.Name, custPurchases

};

Section 66.43: Linq Quantifiers

Quantifier operations return a Boolean value if some or all of the elements in a sequence satisfy a condition. In this article, we will see some common LINQ to Objects scenarios where we can use these operators. There are 3 Quantifiers operations that can be used in LINQ:

All – used to determine whether all the elements in a sequence satisfy a condition. Eg:

int[] array = { 10, 20, 30 };

// Are all elements >= 10? YES array.All(element => element >= 10);

// Are all elements >= 20? NO array.All(element => element >= 20);

// Are all elements < 40? YES array.All(element => element < 40);

Any - used to determine whether any elements in a sequence satisfy a condition. Eg:

int[] query=new int[] { 2, 3, 4 } query.Any (n => n == 3);

Contains - used to determine whether a sequence contains a specified element. Eg:

//for int array

int[] query =new int[] { 1,2,3 }; query.Contains(1);

//for string array

string[] query={"Tom","grey"}; query.Contains("Tom");

//for a string

var stringValue="hello"; stringValue.Contains("h");

Section 66.44: TakeWhile

TakeWhile returns elements from a sequence as long as the condition is true

GoalKicker.com – C# Notes for Professionals

383

int[] list = { 1, 10, 40, 50, 44, 70, 4 };

var result = list.TakeWhile(item => item < 50).ToList();

// result = { 1, 10, 40 }

Section 66.45: Reverse

Inverts the order of the elements in a sequence.

If there is no items throws a ArgumentNullException: source is null.

Example:

// Create an array.

 

int[] array = { 1, 2, 3, 4 };

//Output:

// Call reverse extension method on the array.

//4

var reverse = array.Reverse();

//3

// Write contents of array to screen.

//2

foreach (int value in reverse)

//1

Console.WriteLine(value);

 

 

 

Live code example

Remeber that Reverse() may work di rent depending on the chain order of your LINQ statements.

//Create List of chars

List<int> integerlist = new List<int>() { 1, 2, 3, 4, 5, 6 };

//Reversing the list then taking the two first elements

IEnumerable<int> reverseFirst = integerlist.Reverse<int>().Take(2);

//Taking 2 elements and then reversing only thos two

IEnumerable<int> reverseLast = integerlist.Take(2).Reverse();

//reverseFirst output: 6, 5 //reverseLast output: 2, 1

Live code example

Reverse() works by bu ering everything then walk through it backwards, whitch is not very e cient, but neither is OrderBy from that perspective.

In LINQ-to-Objects, there are bu ering operations (Reverse, OrderBy, GroupBy, etc) and non-bu ering operations (Where, Take, Skip, etc).

Example: Non-bu ering Reverse extention

public static IEnumerable<T> Reverse<T>(this IList<T> list) { for (int i = list.Count - 1; i >= 0; i--)

yield return list[i];

}

Live code example

This method can encounter problems if u mutate the list while iterating.

GoalKicker.com – C# Notes for Professionals

384

Section 66.46: Count and LongCount

Count returns the number of elements in an IEnumerable<T>. Count also exposes an optional predicate parameter

that allows you to filter the elements you want to count.

int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };

int n = array.Count(); // returns the number of elements in the array

int x = array.Count(i => i > 2); // returns the number of elements in the array greater than 2

LongCount works the same way as Count but has a return type of long and is used for counting IEnumerable<T>

sequences that are longer than int.MaxValue

int[] array = GetLargeArray();

long n = array.LongCount(); // returns the number of elements in the array

long x = array.LongCount(i => i > 100); // returns the number of elements in the array greater than 100

Section 66.47: Incrementally building a query

Because LINQ uses deferred execution, we can have a query object that doesn't actually contain the values, but will return the values when evaluated. We can thus dynamically build the query based on our control flow, and evaluate it once we are finished:

IEnumerable<VehicleModel> BuildQuery(int vehicleType, SearchModel search, int start = 1, int count = -1) {

IEnumerable<VehicleModel> query = _entities.Vehicles

.Where(x => x.Active && x.Type == vehicleType)

.Select(x => new VehicleModel { Id = v.Id,

Year = v.Year, Class = v.Class, Make = v.Make, Model = v.Model,

Cylinders = v.Cylinders ?? 0

});

We can conditionally apply filters:

if (!search.Years.Contains("all", StringComparer.OrdinalIgnoreCase)) query = query.Where(v => search.Years.Contains(v.Year));

if (!search.Makes.Contains("all", StringComparer.OrdinalIgnoreCase)) { query = query.Where(v => search.Makes.Contains(v.Make));

}

if (!search.Models.Contains("all", StringComparer.OrdinalIgnoreCase)) { query = query.Where(v => search.Models.Contains(v.Model));

}

if (!search.Cylinders.Equals("all", StringComparer.OrdinalIgnoreCase)) { decimal minCylinders = 0;

decimal maxCylinders = 0; switch (search.Cylinders) {

case "2-4": maxCylinders = 4; break;

GoalKicker.com – C# Notes for Professionals

385

case "5-6": minCylinders = 5; maxCylinders = 6; break;

case "8": minCylinders = 8; maxCylinders = 8; break;

case "10+": minCylinders = 10; break;

}

if (minCylinders > 0) {

query = query.Where(v => v.Cylinders >= minCylinders);

}

if (maxCylinders > 0) {

query = query.Where(v => v.Cylinders <= maxCylinders);

}

}

We can add a sort order to the query based on a condition:

switch (search.SortingColumn.ToLower()) { case "make_model":

query = query.OrderBy(v => v.Make).ThenBy(v => v.Model); break;

case "year":

query = query.OrderBy(v => v.Year); break;

case "engine_size":

query = query.OrderBy(v => v.EngineSize).ThenBy(v => v.Cylinders); break;

default:

query = query.OrderBy(v => v.Year); //The default sorting.

}

Our query can be defined to start from a given point:

query = query.Skip(start - 1);

and defined to return a specific number of records:

if (count > -1) {

query = query.Take(count);

}

return query;

}

Once we have the query object, we can evaluate the results with a foreach loop, or one of the LINQ methods that returns a set of values, such as ToList or ToArray:

SearchModel sm;

//populate the search model here

//...

List<VehicleModel> list = BuildQuery(5, sm).ToList();

GoalKicker.com – C# Notes for Professionals

386