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

//Total = 12

//Even = 6

//FourthItems = [4, 8, 12]

Note that using an anonymous type as the seed one has to instantiate a new object each item because the properties are read only. Using a custom class one can simply assign the information and no new is needed (only when giving the initial seed parameter

Section 66.14: Distinct

Returns unique values from an IEnumerable. Uniqueness is determined using the default equality comparer.

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

var distinct = array.Distinct();

// distinct = { 1, 2, 3, 4, 5 }

To compare a custom data type, we need to implement the IEquatable<T> interface and provide GetHashCode and Equals methods for the type. Or the equality comparer may be overridden:

class SSNEqualityComparer : IEqualityComparer<Person> {

public bool Equals(Person a, Person b) => return a.SSN == b.SSN; public int GetHashCode(Person p) => p.SSN;

}

List<Person> people;

distinct = people.Distinct(SSNEqualityComparer);

Section 66.15: SelectMany: Flattening a sequence of sequences

var sequenceOfSequences = new [] { new [] { 1, 2, 3 }, new [] { 4, 5 }, new [] { 6 } }; var sequence = sequenceOfSequences.SelectMany(x => x);

// returns { 1, 2, 3, 4, 5, 6 }

Use SelectMany() if you have, or you are creating a sequence of sequences, but you want the result as one long sequence.

In LINQ Query Syntax:

var sequence = from subSequence in sequenceOfSequences from item in subSequence

select item;

If you have a collection of collections and would like to be able to work on data from parent and child collection at the same time, it is also possible with SelectMany.

Let's define simple classes

public class BlogPost

{

public int Id { get; set; }

public string Content { get; set; }

public List<Comment> Comments { get; set; }

}

GoalKicker.com – C# Notes for Professionals

362

public class Comment

{

public int Id { get; set; }

public string Content { get; set; }

}

Let's assume we have following collection.

List<BlogPost> posts = new List<BlogPost>()

{

new BlogPost()

{

Id = 1,

Comments = new List<Comment>()

{

new Comment()

{

Id = 1,

Content = "It's really great!",

},

new Comment()

{

Id = 2,

Content = "Cool post!"

}

}

},

new BlogPost()

{

Id = 2,

Comments = new List<Comment>()

{

new Comment()

{

Id = 3,

Content = "I don't think you're right",

},

new Comment()

{

Id = 4,

Content = "This post is a complete nonsense"

}

}

}

};

Now we want to select comments Content along with Id of BlogPost associated with this comment. In order to do

so, we can use appropriate SelectMany overload.

var commentsWithIds = posts.SelectMany(p => p.Comments, (post, comment) => new { PostId = post.Id, CommentContent = comment.Content });

Our commentsWithIds looks like this

{

PostId = 1,

CommentContent = "It's really great!"

},

{

PostId = 1,

GoalKicker.com – C# Notes for Professionals

363

CommentContent = "Cool post!"

},

{

PostId = 2,

CommentContent = "I don't think you're right"

},

{

PostId = 2,

CommentContent = "This post is a complete nonsense"

}

Section 66.16: GroupBy

GroupBy is an easy way to sort a IEnumerable<T> collection of items into distinct groups.

Simple Example

In this first example, we end up with two groups, odd and even items.

List<int> iList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var grouped = iList.GroupBy(x => x % 2 == 0);

//Groups iList into odd [13579] and even[2468] items

foreach(var group in grouped)

{

foreach (int item in group)

{

Console.Write(item); // 135792468 (first odd then even)

}

}

More Complex Example

Let's take grouping a list of people by age as an example. First, we'll create a Person object which has two properties, Name and Age.

public class Person

{

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

}

Then we create our sample list of people with various names and ages.

List<Person> people = new List<Person>(); people.Add(new Person{Age = 20, Name = "Mouse"}); people.Add(new Person{Age = 30, Name = "Neo"}); people.Add(new Person{Age = 40, Name = "Morpheus"}); people.Add(new Person{Age = 30, Name = "Trinity"}); people.Add(new Person{Age = 40, Name = "Dozer"}); people.Add(new Person{Age = 40, Name = "Smith"});

Then we create a LINQ query to group our list of people by age.

var query = people.GroupBy(x => x.Age);

GoalKicker.com – C# Notes for Professionals

364

Doing so, we can see the Age for each group, and have a list of each person in the group.

foreach(var result in query)

{

Console.WriteLine(result.Key);

foreach(var person in result) Console.WriteLine(person.Name);

}

This results in the following output:

20 Mouse 30 Neo

Trinity 40 Morpheus Dozer Smith

You can play with the live demo on .NET Fiddle

Section 66.17: Query collection by type / cast elements to type

interface IFoo { } class Foo : IFoo { } class Bar : IFoo { }

var item0 = new Foo(); var item1 = new Foo(); var item2 = new Bar(); var item3 = new Bar();

var collection = new IFoo[] { item0, item1, item2, item3 };

Using OfType

var foos = collection.OfType<Foo>(); // result: IEnumerable<Foo> with item0 and item1 var bars = collection.OfType<Bar>(); // result: IEnumerable<Bar> item item2 and item3

var foosAndBars = collection.OfType<IFoo>(); // result: IEnumerable<IFoo> with all four items

Using Where

var foos = collection.Where(item => item is Foo); // result: IEnumerable<IFoo> with item0 and item1 var bars = collection.Where(item => item is Bar); // result: IEnumerable<IFoo> with item2 and item3

Using Cast

var bars = collection.Cast<Bar>();

// throws InvalidCastException on the 1st item

var foos = collection.Cast<Foo>();

// throws InvalidCastException on the 3rd item

var foosAndBars = collection.Cast<IFoo>();

// OK

 

 

GoalKicker.com – C# Notes for Professionals

365