Group objects in List<T> by id and order the List by duplicateCount for each object
Solution 1
This will work like you requested:
var list1 = new[] { "u1", "u2", "u3", "u4" };
var list2 = new[] { "u2", "u4", "u5" };
var list3 = new[] { "u4", "u6" };
var allLists = list1.Concat(list2).Concat(list3);
var result = from u in allLists
group u by u into g
orderby g.Count() descending
select g.Key;
And a version with an object instead of string
var list1 = new[] { new User("u1"), new User("u2"), new User("u3"), new User("u4") };
var list2 = new[] { new User("u2"), new User("u4"), new User("u5") };
var list3 = new[] { new User("u4"), new User("u6") };
var allLists = list1.Concat(list2).Concat(list3);
var result = from u in allLists
group u by u.Name into g
orderby g.Count() descending
select g.Key;
Edit: Updated code samples projecting g.Key
instead of only g
.
And here is the Method Chain equivalent of the query above:
var result = allLists
.GroupBy(u => u.Name)
.OrderByDescending(g => g.Count())
.Select(g => g.Key);
Solution 2
Done with strings, but should also work with objects:
var l = new string[] { "user1", "user2", "user3", "user4",
"user2", "user4", "user5" ,
"user4", "user6" };
var result = l.Aggregate(new Dictionary<string, int>(),
(res, user) =>
{ // create a dictionary of all users and their occurence
if (!res.ContainsKey(user)) res[user] = 0;
res[user]++;
return res;
}).OrderByDescending(kvp => kvp.Value) // order by incidence
.Select(kvp => kvp.Key); // select user names only
foreach (var user in result) Console.WriteLine(user);
Comments
-
ThdK almost 2 years
I have multiple List with objects. But some of the items in one list, also exists in other lists. My question is how can I merge all the items of all the lists into one final list. So there are no duplicates in that list and the items are sorted on the number of duplicates each item had in the different lists.
Example
List1: [users1, user2, user3, user4]
List2: [user2, user4, user5]
List3: [user4,user6]result: [user4, user2, user1, user3, user5, user6]
(the order of users with the same count doesn't matter)
I tried something like this:
List<User> finalResults = list1.Concat(list2).ToList<User>(); var q = finalResults.GroupBy(x => x.id) .Select(g => new User { name = g.First().name, count = g.Count() }) .OrderByDescending(usr => usr.count); finalResults = q.ToList<User>();
but the result is an empty list.
Thanks in advance!
-
Nasmi Sabeer about 13 years@MikeEast projection should be g.Key
-
Steven Jeuris about 13 yearsStrange, I would expect this solution to be less performant than paulmey's solution, however, it's the other way around. (Not that clarity doesn't win as long as performance isn't an issue.) I was just wondering what this would compile to which is more performant than the other solution.
-
Mikael Östberg about 13 years@Steven, I don't think there is such a big performance difference. This might even be performing better.
-
Steven Jeuris about 13 years@MikeEast: It is performing better. ;p (at least for big collections on my pc)
-
Mikael Östberg about 13 years@Steven, Mine too: 4741ms vs 3467ms over 1M iterations on the collection in the example.
-
Mikael Östberg about 13 years@Steven, It's probably the grouping that requires the extra time. Anyway - for any normal usage this is not a big difference. And for the cases you depend on that difference, I think you have chosen the wrong language to begin with. :)