Reputation: 37
Hello I am trying to split the results from a string into a dictionary so I can add the numbers together. This is information received from a texting api a client will text in an account + the amount they want to donate and multiple accounts are separated by commas ex th 20.00, bf 10.00 etc.
When I run the code it worked find in windows form's but when i converted over to MVC I get the error "an item with the same key has already been added" which i know means its duplicating an key. I tried entering an if statement during the foreach loop:
if(!tester.containsKey(j){}
but that did not always solve the problem and created a new error about out of range. Below is my current code:
public ActionResult register(text2give reg)
{
string body = reg.body;
try
{
var items = body.Split(',');
Dictionary<string, float> tester = new Dictionary<string, float>();
var j = 0;
var total = 0f;
while (j < body.Length)
{
foreach (var item in items)
{
var s = item.Trim().Split(' ');
tester.Add(s[0], float.Parse(s[1]));
total += float.Parse(s[1]);
j++;
}
}
ViewBag.total = total;
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
return View(reg);
}
Upvotes: 0
Views: 9023
Reputation: 1169
s[0] is the duplicate key not j. You would need to use the following
var s = item.Trim().Split(' ');
if(!tester.containsKey(s[0]){
tester.Add(s[0], float.Parse(s[1]));
total += float.Parse(s[1]);
j++;
}
You might be getting duplicate data, be careful ignoring the keys as you might actually need the data. I'm just showing you how to suppress the error.
Upvotes: 1
Reputation: 28737
Your code is OK, but it makes quite a few assumptions:
Here's how I would write this code to make sure it correctly guards against these cases:
public ActionResult register(text2give reg)
{
string body = reg.body;
try
{
var items = body.Split(',');
var splitItems = items.Select(i => i.Split(' ')).ToList();
var itemsWithTwoValues = splitItems.Where(s => s.Length == 2);
var uniqueItems = itemsWithTwoValues.GroupBy(s => s[0])
.Where(g => g.Count() == 1)
.SelectMany(g => g);
var tester = uniqueItems.ToDictionary(s => s[0], s => float.Parse(s[1]));
var total = tester.Sum(s => s.Value);
ViewBag.total = total;
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
return View(reg);
}
Or, the shorter, condensed version:
public ActionResult register(text2give reg)
{
string body = reg.body;
try
{
var tester = body.Split(',') // Split the initial value into items
.Select(i => i.Split(' ')) // Split each item into elements
.Where(s => s.Length == 2) // Take only those that have 2 items
.GroupBy(s => s[0]) // Group by the key
.Where(g => g.Count() == 1) // Remove all those that have a duplicate key
.SelectMany(g => g) // Ungroup them again
.ToDictionary(s => s[0],
s => float.Parse(s[1])); // Create a dictionary where the first item is the key and the second is the parsed float
var total = tester.Sum(s => s.Value);
ViewBag.total = total;
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
return View(reg);
}
Upvotes: 3