Reputation: 6531
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 multiple Tags associated with it, and the same Tag can be used in any number of different Photos.
What I ultimately want to do is to retrieve a list of distinct tags, with a count of how many photos are assigned to each tag.
I have no control over the underlying data - I am using an API which has a Search method that I'm using to retrieve a collection of Photos, but there is no method to get a list of distinct tags.
So my question is, if I have a large collection of Photos, how can I use LINQ to get a distinct list of the tags contained within this list, and get the count (of photos) for each of those tags?
Upvotes: 8
Views: 1310
Reputation: 21795
You can use SelectMany
& GroupBy
like this:-
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 respective PhotoIds
in comma separated format.
Update:
Sorry, Just noticied you want the count of Photos
object, in that case you simply need this:-
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 below output:-
Upvotes: 3
Reputation: 79441
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 reasoning is as follows.
Upvotes: 9
Reputation: 21487
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
Upvotes: 0
Reputation: 223187
You can do that in two steps.
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)));
}
Upvotes: 0