C
C#14mo ago
MikeInvise

❔ Using Linq to Add or Update Score in Highscore List Object

Hi, I created a Highscore object, which consists of an IntValue and StringValue objects. I am trying to use Linq to add or update a highscore to the list. The list contains a name and the corresponding score. I want to be able to project a name and if the name exists, select it's IntValue and add to it the score, otherwise, if the projected name does not exist within the object, I want to add it. I was thinking of something like highscores.Where(x => x.StringValue.Equals("Player).AddOrUpdate(y=>y.IntValue+=thisScore)); I thought maybe I would need to create my own IEnumberable AddOrUpdate, and I tried to make something, but then I got really stuck. At this point I really don't know what I am doing, but I really want to understand and know how to do this. I would very much prefer not to use Fors and ForEachs within this code, because I have multiple if statements in a block that are running inside a for loop, and they are one lines. If I have to do long hand code, I'm going to have to copy and paste that 8 times and make it really messy and complicated. Thank you in advance for the help!
4 Replies
Angius
Angius14mo ago
What's your current code for that .AddOrUpdate() method?
MikeInvise
MikeInviseOP14mo ago
This is what I have public class Highscore { public string StringValue { get; set; } public int IntValue { get; set; } public Highscore(string stringValue, int intValue) { StringValue = stringValue; IntValue = intValue; } } public static class HighscoreExentions { public static IEnumerable<Highscore> AddOrUpdate( this IEnumerable<Highscore> highscores, string name, int value=0) { if (highscores.Any(x => x.StringValue == name)) { highscores.Where(x => x.StringValue == name).Select(y => y.IntValue += value); } else { highscores.ToList().Add(new Highscore(name, value)); } return highscores; } } Before I wrote this post, I didn't even have that, because I was trying to do it without an extension method, or as minimally as possible. I thought I could cast or project a propsed value and use something like DefaultIfEmpty or Where to add or update. This looks like it loops through the list several times, and in that several more times. I want to be as efficient as possible, as the highscore list could end up be hundreds, of entries long. I had an issue in another part of the project, where I was looping through a list inside another loop, both lists were several hundred entries long, and I was originally doing that to select items that matched each other, and then do something with that. That loop inside a loop then perform, I found was taking 40 seconds, and I have a Ryzen 7 3700 8 Core CPU.
reflectronic
reflectronic14mo ago
LINQ is for queries, and not really meant for doing updates/mutations. the issue you are running into here is because of that LINQ uses deferred execution. when you do highscores.Where(x => x.StringValue == name).Select(y => y.IntValue += value);, it returns an IEnumerable<int> object that represents the query, but it does not actually do the query until you start enumerating elements from that object in other words, the code you have in the if block does exactly nothing the code you have in your else also does nothing, but for a different reason. when you call highscores.ToList(), it copies all of the elements enumerated from highscores into a new list. you do not save that list anywhere, so all that work is thrown away it is pretty easy to create a functional alternative to AddOrUpdate, which might look something like:
internal static class HighscoreExentions
{
public static void AddOrUpdateHighscores(this List<Highscore> list, string name, int value = 0)
{
bool hasMatchingElement = false;
foreach (var highscore in list)
{
if (highscore.StringValue == name)
{
hasMatchingElement = true;
highscore.IntValue += value;
}
}

if (!hasMatchingElement)
{
list.Add(new Highscore(name, value));
}
}
}
internal static class HighscoreExentions
{
public static void AddOrUpdateHighscores(this List<Highscore> list, string name, int value = 0)
{
bool hasMatchingElement = false;
foreach (var highscore in list)
{
if (highscore.StringValue == name)
{
hasMatchingElement = true;
highscore.IntValue += value;
}
}

if (!hasMatchingElement)
{
list.Add(new Highscore(name, value));
}
}
}
this is as efficient as an operation like this can be since you mentioned you were running into problems, though, the best solution may be an entirely different approach
Accord
Accord14mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server