Justin Budd
Justin Budd

Reputation: 37

an item with the same key has already been added mvc

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

Answers (2)

Ryan Gunn
Ryan Gunn

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

Kenneth
Kenneth

Reputation: 28737

Your code is OK, but it makes quite a few assumptions:

  • It assumes the body is split properly
  • It assumes all items are unique (apparently they aren't, hence the error)
  • It assumes there are two elements in each item (it isn't, hence the indexOutOfRangeException)

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

Related Questions