Reputation: 552
I am trying to calculate the occurrences of an Item in a list using LINQ,
I have the following schema -
User (All Entries Provided), Count (To be Calculated)
The count should be like -
I cannot think of an elegant solution to this.
Is it even possible only using LINQ? If not, how can we achieve this using LINQ with some C# Code.
Upvotes: 11
Views: 16402
Reputation: 39277
You can do it without double iterating the set like this:-
var values = "ABAABCA".ToArray();
var counts = new Dictionary<char, int>();
var counter = values.Select(ch =>
{
int count = counts[ch] = counts.ContainsKey(ch) ? counts[ch] + 1 : 1;
return new {ch, count};
});
foreach (var c in counter)
Console.WriteLine(c.ch + " -> " + c.count);
Upvotes: 1
Reputation: 1
I did this by using Select. I was writing a sync function that got items from the World of Warcraft API and certain items weren't on the API anymore, even though they technically were still in the game. Since I was syncing items in order of number of times they were listed on the auction house, it would get stuck on these certain items.
I created a list of bad item IDs. If the item wouldn't sync, I added it to the list. I wanted to skip the item if it couldn't sync 3 times. I accomplished that with the following code:
private int[] GetBadItemList()
{
var ids = from i in _badItemIDs
where _badItemIDs.Select(curItem => curItem.Equals(i)).Count() >= MAX_ITEM_TRYS
select i;
return ids.ToArray();
}
Upvotes: 0
Reputation: 223237
You can do that with a combination of loop and Enumerable.Take
, Something like:
for (int i = 0; i < list.Count; i++)
{
//Get count of current element to before:
int count = list.Take(i+1)
.Count(r => r.UserName == list[i].UserName);
list[i].Count = count;
}
Where your list
is defined as:
List<User> list = new List<User>
{
new User{UserName = "A"},
new User{UserName = "B"},
new User{UserName = "A"},
new User{UserName = "A"},
new User{UserName = "B"},
new User{UserName = "A"},
new User{UserName = "C"},
new User{UserName = "A"},
};
and User
class as:
public class User
{
public string UserName { get; set; }
public int Count { get; set; }
}
Later you can print the output like:
foreach (var item in list)
{
Console.WriteLine("UserName: {0}, Running Total: {1}", item.UserName, item.Count);
}
and you will get:
UserName: A, Running Total: 1
UserName: B, Running Total: 1
UserName: A, Running Total: 2
UserName: A, Running Total: 3
UserName: B, Running Total: 2
UserName: A, Running Total: 4
UserName: C, Running Total: 1
UserName: A, Running Total: 5
Upvotes: 3
Reputation: 245419
Can it be done with LINQ? Probably not easily. Can it be done with your own extension method fairly easily? Sure (I haven't actually tried to compile and run the code so I can't guarantee that it'll work, but it's definitely a good starting point):
public static IEnumerable<Tuple<T, int>> RunningTotal<T>(this IEnumerable<T> source)
{
var counter = new Dictionary<T, int>();
foreach(var s in source)
{
if(counter.ContainsKey(s))
{
counter[s]++;
}
else
{
counter.Add(s, 1);
}
yield return Tuple.Create(s, counter[s]);
}
}
Upvotes: 3