C# Looping through Dictionary and summing values for Keys - c#

I have a Dictionary<string, decimal?>, and i would like to be able to sum the decimals by distinct string. So say i have the below inputs in dictionary,
"1", 20.00
"1", 35.00
"2", 10.00
"3", 15.00
"3", 30.00
I would like the following output to a new Dictionary
"1", 55.00
"2", 10.00
"3", 45.00
I'm guessing it would be something like
foreach(var item in dictionary)
{
newDictionary.Add(not sure what would go here, maybe some sort of linq query for distinct and sum?);
}

Assuming the same List of key value pairs as in the other answers:
var myList = New List<KeyValuePair<string, decimal?>> {
new KeyValuePair<string, decimal?>("1", (decimal)10.00),
new KeyValuePair<string, decimal?>("1", (decimal)15.00),
new KeyValuePair<string, decimal?>("2", (decimal)20.00),
new KeyValuePair<string, decimal?>("3", (decimal)30.50),
new KeyValuePair<string, decimal?>("3", (decimal)17.500)
};
var myResults = myList.GroupBy(p => p.Key)
.ToDictionary(g => g.Key, g=>g.Sum(p=>p.Value))

The keys in a dictionary can't be repeated, so the 2 first entries won't fit in a dictionary.
I think you may have a list of objects that you can loop, then you can use a dictionary to store the total for each "key"
something like
Dictionary<string, double> totals = new Dictionary<string, double>();
List<Tuple<string, double>> entries = new List<Tuple<string, double>>() {
new Tuple<string, double>("1",20.00),
new Tuple<string, double>("1",35.00),
new Tuple<string, double>("2",10.00),
new Tuple<string, double>("3",15.00),
new Tuple<string, double>("3",30.00)
};
foreach (var e in entries)
{
if (!totals.Keys.Contains(e.Item1))
{
totals[e.Item1] = 0;
}
totals[e.Item1] += e.Item2;
}

You can not have Dictionary object with duplicate keys. You would see ArgumentException when you try to add an existing key into the Dictionary object.
Refer: https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx

As mentioned here You can't use Dictionary if you are using same keys, because they must be Unique.
You can use list of KeyPair though, which is closest to Dictionary, then you're code will look like this:
List<KeyValuePair<string, decimal?>> myList = new List<KeyValuePair<string, decimal?>>();
myList.Add(new KeyValuePair<string, decimal?>("1", (decimal)10.00));
myList.Add(new KeyValuePair<string, decimal?>("1", (decimal)15.00));
myList.Add(new KeyValuePair<string, decimal?>("3", (decimal)30.50));
myList.Add(new KeyValuePair<string, decimal?>("3", (decimal)17.500));
Dictionary<string, decimal?> sums = new Dictionary<string, decimal?>(); //This can be a dictionary because the keys will be unique after grouping
foreach (var item in myList.GroupBy(m => m.Key))
{
string currentKey = item.FirstOrDefault().Key;
sums.Add(currentKey, myList.Where(j => j.Key == currentKey).Sum(o => o.Value));
}

Related

How to get nested key value pair from dictionary with linq [duplicate]

This question already has answers here:
C# String replace with dictionary
(8 answers)
Closed 3 years ago.
I have a lstSubs List<KeyValuePair<string, string>
which contain value
FNAME, "ABC"
LNAME ,"XYZ"
VAR001, "VAR002"
VAR002 , "ActualValueforVAR001"
VAR003, "VAR004"
VAR004 , "VAR005"
VAR005, "ActualValueforVAR003"
I have a String like envelop "Hello [FNAME] [LNAME] you have created a request for [VAR001] which got assigned to [VAR003]"
var regex = new Regex(#"\[(.*?)\]");
var matches = regex.Matches(envelop.ToString());
foreach (Match match in matches)
{
columnValue = linq to get the value from the list based on key;
envelop.Replace(match.Value, columnValue);
}
in this, The straight Key,Value pairs are easy to get via Linq but I am getting tough time to fetch the complex values which are nested in terms of connected Key, Value.
is there any way in LINQ or have to go with a loop.
Expected Output : Hello ABC XYZ you have created a request for ActualValueforVAR001 which got assigned to ActualValueforVAR003
Thanks,
PS. The code is not complete. it's a part of entire code edited with an intention to make it concise to issue
Edited: some of my text was not visible due to formatting.
They Dictionary values are nested as I am creating them based on some conditions in which they got configured
First, let's turn initial List<T> into a Dictionary<K, V>:
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>() {
new KeyValuePair<string, string>("FNAME", "ABC"),
new KeyValuePair<string, string>("LNAME", "XYZ"),
new KeyValuePair<string, string>("VAR001", "VAR002"),
new KeyValuePair<string, string>("VAR002", "ActualValueforVAR001"),
new KeyValuePair<string, string>("VAR003", "VAR004"),
new KeyValuePair<string, string>("VAR004", "VAR005"),
new KeyValuePair<string, string>("VAR005", "ActualValueforVAR003"),
};
Dictionary<string, string> dict = list.ToDictionary(
pair => pair.Key,
pair => pair.Value,
StringComparer.OrdinalIgnoreCase); // Comment out if should be case sensitive
// Some values can be nested
while (true) {
bool nestedFound = false;
foreach (var pair in dict.ToList()) {
if (dict.TryGetValue(pair.Value, out var newValue)) {
dict[pair.Key] = newValue;
nestedFound = true;
}
}
if (!nestedFound)
break;
}
Then for a given envelop
string envelop =
#"Hello [FNAME] [LNAME] you have created a request for [VAR001] which got assigned to [VAR003]";
you can put a simple Regex.Replace:
string result = Regex
.Replace(envelop,
#"\[[A-Za-z0-9]+\]",
m => dict.TryGetValue(m.Value.Trim('[', ']'), out var value) ? value : "???");
Console.Write(result);
Outcome:
Hello ABC XYZ you have created a request for ActualValueforVAR001 which got assigned to ActualValueforVAR003

Manipulating data in C# Set operations

I have two lists of dictionary on which I am doing set operations. I will illustrate what I am doing and what I am trying to achieve as an example:
var A = new List<Dictionary<string, int>>();
var B = new List<Dictionary<string, int>>();
A.Add(new Dictionary <string, int> { {"KeyA",1}, {"KeyB", 2} });
A.Add(new Dictionary <string, int> { {"KeyA",3}, {"KeyB", 5} });
B.Add(new Dictionary <string, int> { {"KeyA",6}, {"KeyB", 8}, {"KeyC", 11} });
B.Add(new Dictionary <string, int> { {"KeyA",3}, {"KeyB", 7}, {"KeyC", 15} });
var result = A.Intersect(B, new KeyComparer("KeyA"));
This gives me back the list of A using KeyA for intersection and I get a single row with {"KeyA",3}, {"KeyB", 5} as the result. What if I want to add {KeyC, 15} from B to the result when intersection has happened.
I hope I am clear with the question.
If I've correctly understood your question, you want to add some other item to the sequence once you've done the intersection... and then, what you need is Enumerable.Concat:
var result = A.Intersect(B, new KeyComparer("KeyA"))
.Concat(B.Last().Where(pair => pair.Key == "KeyC"));

Fastest way to retrieve values from dictionary

I have a var myDictionary = new Dictionary<int, string> with the following data:
123, "Do this"
234, "Do that"
345, "Do something"
123, "Do that"
567, "Do anything"
234, "Do something"
What's the best way for me to retrieve only the values for any given key? Say, I want to get only the values for 123.
If you want to have multiple different values grouped under one key you probably have to change the structure of your dictionary to something like this:
var myDictionary = new Dictionary<int, List<string>>();
You then initialize the list for each new key or if the key's already there you add the item to the list.
if (!myDictionary.ContainsKey(myKey))
{
myDictionary[myKey] = new List<string();
}
myDictionary[myKey].Add(myItem);
And you get the items in a standard way:
if (myDictionary.ContainsKey(myKey))
{
var results = myDictionary[myKey];
}
This will give you a list that you can then query to see what items have been returned.
A Dictionary object cannot have multiple items with the same key. Instead, you want to use KeyValuePair.
The code might look something like this:
var items = new List<KeyValuePair<int, String>>();
items.Add(new KeyValuePair<int, String>(123, "Do this"));
items.Add(new KeyValuePair<int, String>(234, "Do that"));
items.Add(new KeyValuePair<int, String>(345, "Do something"));
items.Add(new KeyValuePair<int, String>(123, "Do that"));
items.Add(new KeyValuePair<int, String>(567, "Do anything"));
items.Add(new KeyValuePair<int, String>(234, "Do something"));
// This is the key you are looking for
int desiredValue = 123;
foreach (var v in items.Where(kvp => kvp.Key == desiredValue))
{
// Access the values you need here
Console.WriteLine(v.Value);
}
Where the output would be:
Do this
Do that
You can see this example in action here. Happy coding :)
See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication61
{
class Program
{
static void Main(string[] args)
{
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>() {
{123, new List<string>() {"Do this", "Do that"}},
{234, new List<string>() {"Do that", "Do something"}},
{345, new List<string>() {"Do something"}},
{567, new List<string>() {"Do anything"}}
};
List<string> results = dict[123];
}
}
}

Get the value from list

I create the list like
var list = new List<KeyValuePair<string, string>>();
list.Add(new KeyValuePair<string, string>("1", "abc"));
list.Add(new KeyValuePair<string, string>("2", "def"));
list.Add(new KeyValuePair<string, string>("3", "ghi"));
How to select the value from this list.
Which means I need to pass 1 to the list and need to take the equal value "abc".How to do this? input is 1,output is abc.
It sounds like you just want:
var value = list.First(x => x.Key == input).Value;
That's if you're sure the key will be present. It's slightly trickier otherwise, partly because KeyValuePair is a struct. You'd probably want:
var pair = list.FirstOrDefault(x => x.Key == input);
if (pair.Key != null)
{
// Yes, we found it - use pair.Value
}
Any reason you're not just using a Dictionary<string, string> though? That's the more natural representation of a key/value pair collection:
var dictionary = new Dictionary<string, string>
{
{ "1", "abc" },
{ "2", "def" },
{ "3", "ghi" }
};
Then:
var value = dictionary[input];
Again, assuming you know the key will be present. Otherwise:
string value;
if (dictionary.TryGetValue(input, out value))
{
// Key was present, the value is now stored in the value variable
}
else
{
// Key was not present
}
Why are you not using a Dictionary? http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
It seems to me this would solve your problem, and it's much easier to use.

Converting a dictionary key in double

I think it is not complicated but after doing some research I can't find an answer to a simple problem.
I am iterating through keys in a dictionary and I would like to use the key which is a string as a double in some calculation.
If I do this :
foreach (KeyValuePair<string, List<string> price in dictionary)
double ylevel = Convert.ToDouble(price.Key);
It seems to not work and I get a "Input string was not in a correct format" error.
What is the right way to get a double from the key..
Thanks
Bernard
You're doing it correctly.
The error message indicates that one of your keys is not actually a double.
If you step through this example in a debugger, you'll see it fails on the second item:
var dictionary = new Dictionary<string, List<string>>();
dictionary.Add("5.72", new List<string> { "a", "bbb", "cccc" });
dictionary.Add("fifty two", new List<string> { "a", "bbb", "cccc" });
foreach (KeyValuePair<string, List<string>> price in dictionary)
{
double ylevel = Convert.ToDouble(price.Key);
}
Solution
To resolve this problem, you should use the following code:
var dictionary = new Dictionary<string, List<string>>();
dictionary.Add("5.72", new List<string> { "a", "bbb", "cccc" });
dictionary.Add("fifty two", new List<string> { "a", "bbb", "cccc" });
foreach (KeyValuePair<string, List<string>> price in dictionary)
{
double ylevel;
if(double.TryParse(price.Key, out ylevel))
{
//do something with ylevel
}
else
{
//Log price.Key and handle this condition
}
}
This is telling you that the string (that happens to be the key, although this is unrelated to the problem) cannot be parsed into a double. Check the value of the string you are attempting to convert.
double ylevel = Convert.ToDouble(price.Key.GetHashCode());

Categories

Resources