LINQ differs from corresponding counters based on List property

I have the following class

public class Photo { public int Id { get; set; } public string Caption { get; set; } public Collection<string> Tags { get; set; } } 

A photo can have several tags associated with it, and the same tag can be used in any number of different photos.

What I ultimately want to do is get a list of different tags with a count of the number of photos assigned to each tag.

I have no control over the underlying data. I use an API that has a search method that I use to get a collection of photos, but there is no way to get a list of different tags.

So my question is: if I have a large collection of photos, how can I use LINQ to get a separate list of tags from this list and get the number (of photos) for each of these tags?

+7
c # linq
source share
4 answers
 var tagCounts = photos .SelectMany(photo => photo.Tags) .GroupBy(tag => tag, (tag, group) => new { tag, count = group.Count() }) .ToDictionary(tuple => tuple.tag, tuple => tuple.count); 

The rationale is as follows:

  • Get the sequence of all tags with a repeat if multiple photos have the same tag.
  • Group repeating tags by their value and count the number of tags in each group.
  • Build a dictionary mapping from each tag with the number of photos that have this tag.
+8
source share

You can use SelectMany and GroupBy as follows: -

 var result = photos.SelectMany(x => x.Tags, (photosObj, tags) => new {photosObj, tags}) .GroupBy(x => x.tags) .Select(x => new { Tags = x.Key, PhotoId = String.Join(",",x.Select(z => z.photosObj.Id)) }); 

This will give you all the tags and their corresponding PhotoIds in comma separated format.

Update:

Sorry, you just need to count the number of Photos objects, in which case you just need to: -

 var result = photos.SelectMany(x => x.Tags) .GroupBy(x => x) .Select(x => new { Tags = x.Key, PhotoCount = x.Count() }); 

So, suppose you have this data: -

  List<Photo> photos = new List<Photo> { new Photo { Id =1, Caption = "C1", Tags = new List<string> { "T1", "T2", "T3" }}, new Photo { Id =2, Caption = "C2", Tags = new List<string> { "T4", "T2", "T5" }}, new Photo { Id =3, Caption = "C3", Tags = new List<string> { "T5", "T3", "T2" }} }; 

You will see below: -

enter image description here

+2
source share

You can do this in two steps.

  • First select tags from the list.
  • Go through the various tags and get the count from the list and put it in Dictionary<string,int>

Something like:

 List<Photo> list = new List<Photo>(); var distinctTags = list.SelectMany(r => r.Tags).Distinct(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (string tag in distinctTags) { dictionary.Add(tag, list.Count(r=> r.Tags.Contains(tag))); } 
0
source share
 var list=new[]{ new {id=1,Tags=new List<string>{"a","b","c"}}, new {id=2,Tags=new List<string>{"b","c","d"}}, new {id=3,Tags=new List<string>{"c","d","e"}}, }; var result=list.SelectMany(r=>r.Tags) .GroupBy(r=>r,r=>r,(Key,Vals)=>new {Tag=Key,Count=Vals.Count()}); 

Result:

 Tag Count a 1 b 2 c 3 d 2 e 1 
0
source share

All Articles