Updating a dictionary dynamically with foreach - c#

When trying to update a Dictionary with the following:
foreach(KeyValuePair<string, string> pair in dict)
{
dict[pair.Key] = "Hello";
}
And exception is thrown. Is there any way to dynamically update the dictionary WITHOUT making any kind of key or value backups?
EDIT!!!!!! View code. I realized that this portion was actually doable. The real case is this. I thought they would be the same, but they are not.
foreach(KeyValuePair<string, string> pair in dict)
{
dict[pair.Key] = pair.Key + dict[pair.Key];
}

Any reason why you're not iterating over the keys?
foreach(var key in dict.Keys)
{
dict[key] = "Hello";
}

You can either loop over the dictionary (you need to use ToList because you can't change a collection that is being looped over in a foreach loop)
foreach(var key in dict.Keys.ToList())
{
dict[key] = "Hello";
}
or you can do it in one line of LINQ as you're setting the same value to all the keys.
dict = dict.ToDictionary(x => x.Key, x => "Hello");
Updated question
foreach (var key in dict.Keys.ToList())
{
dict[key] = key + dict[key];
}
and the LINQ version
dict = dict.ToDictionary(x => x.Key, x => x.Key + x.Value);
If you want to avoid using ToList, you can use ElementAt so that you can modify the collection directly.
for (int i = 0; i < dict.Count; i++)
{
var item = dict.ElementAt(i);
dict[item.Key] = item.Key + item.Value;
}

Related

IDictionary<String, List<OpenXmlCompositeElement>> - get the List<OpenXmlCompositeElement>?

I'm working with Open XML & I have a IDictionary<String, List<OpenXmlCompositeElement>> structure. I want to work with the List part of the structure but this.map.Values tries to wrap it in an ICollection. How can I get the List part from my structure?
public List<OpenXmlCompositeElement> MapData()
{
//this does not work
return this.map.Values;
}
Since it is a dictionary, it expects you to tell from which key you want the value.
So this would be the code you need, where yourKey is the key you want to retrieve:
public List<OpenXmlCompositeElement> MapData()
{
return this.map["yourKey"];
}
If you have no interest in the key, and the dictionary is just a dictionary because the serializer says so, you could get the first item for example like this:
public List<OpenXmlCompositeElement> MapData()
{
return this.map.Values.First();
}
You can either loop through the dictionary and use the value you would like, or access the List directly using the key (in this case it's a string)
IDictionary<String, List<OpenXmlCompositeElement>> myDictionary;
List<OpenXmlCompositeElement> myList = myDictionary["myKey"];
Where myKey is available in the dictionary.
Alternatively you can loop through
foreach (var item in myDictionary)
{
var key = item.Key;
var value = item.Value
// You could then use `key` if you are unsure of what
// items are in the dictionary
}
Assuming this is your dictionary...
IDictionary<string, List<OpenXmlCompositeElement>> items = ...;
Get a specific List by key...
List<OpenXmlCompositeElement> list = items["key"];
Get the first list in the dictionary...
List<OpenXmlCompositeElement> list = items.Values.First();
Concatenate all lists in the dictionary into a single list...
List<OpenXmlCompositeElement> list = items.SelectMany(o => o).ToList();
foreach(KeyValuePair<string, List<OpenXmlCompositeElement>> kvp in IDictionary)
{
string key = kvp.key
List<OpenXmlCompositeElement> list = kvp.Value;
foreach(OpenXmlCompositeElement o in list)
{
Do anything you need to your List here
}
}
I am working with dictionaries as well, so here is a real example that I am currently working with:
foreach(KeyValuePair<string, List<DataRecords>> kvp in vSummaryResults)
{
string sKey = kvp.Key;
List<DataRecords> list = kvp.Value;
string[] vArr = sKey.Split(',');
int iTotalTradedQuant = 0;
double dAvgPrice = 0;
double dSumQuantPrice = 0;
double dQuantPrice = 0;
double dNumClose = 0;
foreach (DataRecords rec in list)
{
if(vSummaryResults.ContainsKey(sKey))
{
iTotalTradedQuant += rec.iQuantity;
dQuantPrice = rec.iQuantity * rec.dInputTradePrice;
dSumQuantPrice += dQuantPrice;
dAvgPrice = dSumQuantPrice / iTotalTradedQuant;
dNumClose = rec.dNumericClosingPrice;
}
else
{
vSummaryResults.Add(sKey, list);
//dNumClose = rec.dNumericClosingPrice;
}

How to compare key/value dictionary with == operator on a IReadOnlyCollection<string>?

I have a MultiValueDictionary<string, string> where I am trying to get a key by value.
var dic = na.prevNext; // Getter to get MultiValueDictionary
string nodePointingToThisOne = "";
foreach (var item in dic)
{
if(item.Value == "test")
{
nodePointingToThisOne = item.Key;
}
break;
}
This does not work so I tried Linq:
string nodePointingToThisOne = dic.Where(x => x.Value == this.nodeID).Select(x => x.Key);
But on both I get this error: Operator '==' cannot be applied to operands of type 'System.Collections.Generic.IReadOnlyCollection<string>' and 'string'
So my question is how do I make this comparison work for a read-only collection? I am aware that I get problems if a key exists multiple times but I reduced the problem to this one for now.
I read
Get Dictionary key by using the dictionary value
LINQ: Getting Keys for a given list of Values from Dictionary and vice versa
get dictionary key by value
Getting key of value of a generic Dictionary?
Get key from value - Dictionary<string, List<string>>
but they deal with a "normal" dictionary.
Since the Value property it self may contain multiple values you can't compare it directly against certain string using == operator. Use Contains() instead :
.....
if (item.Value.Contains("test"))
{
.....
}
...or in method chain version :
string nodePointingToThisOne = dic.Where(x => x.Value.Contains("test"))
.Select(x => x.Key)
.FirstOrDefault();
Try to iterate by Keys and then compare the value, and return the Key only if the Value matches.
Like this:
foreach (var key in dic.Keys)
{
if(dic[key].Contains("your value"))
return key;
}
You can iterate over keys like this
foreach (var key in dic.Keys)
{
if(key == "your key")
return key;
}
You can also iterate over values like this
foreach (var v in dic.Values)
{
if(v == "your value")
return v;
}
Example:
Dictionary<string, string> c = new Dictionary<string, string>();
c.Add("Pk", "Pakistan");
c.Add("Aus", "Australia");
c.Add("Ind", "India");
c.Add("Nz", "New Zeland");
c.Add("SA", "South Africa");
foreach (var v in c.Values)
{
if (v == "Australia")
{
Console.WriteLine("Your Value is = " + v);
// perform your task
}
}
foreach (var k in c.Keys)
{
if (k == "Aus")
{
// perform your task
Console.WriteLine("Your Key is = " + k);
}
}
Output:
Your Value is = "Australia"
Your Key is = "Aus"
If you look at the MultiValueDictionary, line 81 will give you a hint. It is:
[TestInitialize]
public void TestInitialize()
{
MultiValueDictionary = new MultiValueDictionary<TestKey, string>();
}
protected static void AssertAreEqual( IDictionary<TestKey, string[]> expected,
IMultiValueDictionary<TestKey, string> actual )
{
Assert.AreEqual( expected.Count, actual.Count );
foreach ( var k in expected.Keys )
{
var expectedValues = expected[ k ];
var actualValues = actual[ k ];
AssertAreEqual( expectedValues, actualValues );
}
}
So for your case, the solution is similar:
foreach (var item in dic.keys)
{
if(dict[item] == "test")
{
nodePointingToThisOne = item;
return nodePointingToThisOne;
}
}
worked for me:
foreach (int i in Dictionary.Keys)
{
if (Dictionary.Values.ToString() == "Your Value")
{
return Dictionary.Keys;
}
}

using a for loop to iterate through a dictionary

I generally use a foreach loop to iterate through Dictionary.
Dictionary<string, string> dictSummary = new Dictionary<string, string>();
In this case I want to trim the entries of white space and the foreach loop does however not allow for this.
foreach (var kvp in dictSummary)
{
kvp.Value = kvp.Value.Trim();
}
How can I do this with a for loop?
for (int i = dictSummary.Count - 1; i >= 0; i--)
{
}
what about this?
for (int i = dictSummary.Count - 1; i >= 0; i--) {
var item = dictSummary.ElementAt(i);
var itemKey = item.Key;
var itemValue = item.Value;
}
KeyValuePair<TKey, TValue> doesn't allow you to set the Value, it is immutable.
You will have to do it like this:
foreach(var kvp in dictSummary.ToArray())
dictSummary[kvp.Key] = kvp.Value.Trim();
The important part here is the ToArray. That will copy the Dictionary into an array, so changing the dictionary inside the foreach will not throw an InvalidOperationException.
An alternative approach would use LINQ's ToDictionary method:
dictSummary = dictSummary.ToDictionary(x => x.Key, x => x.Value.Trim());
You don't need to use .ToArray() or .ElementAt(). It is as simple as accessing the dictionary with the key:
dictSummary.Keys.ToList().ForEach(k => dictSummary[k] = dictSummary[k].Trim());

C#: Remove duplicate values from dictionary?

How can I create a dictionary with no duplicate values from a dictionary that may have duplicate values?
IDictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("1", "blue");
myDict.Add("2", "blue");
myDict.Add("3", "red");
myDict.Add("4", "green");
uniqueValueDict = myDict.???
Edit:
-I don't care which key is kept.
- Is there something using Distinct() operation?
What do you want to do with the duplicates? If you don't mind which key you lose, just build another dictionary like this:
IDictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("1", "blue");
myDict.Add("2", "blue");
myDict.Add("3", "red");
myDict.Add("4", "green");
HashSet<string> knownValues = new HashSet<string>();
Dictionary<string, string> uniqueValues = new Dictionary<string, string>();
foreach (var pair in myDict)
{
if (knownValues.Add(pair.Value))
{
uniqueValues.Add(pair.Key, pair.Value);
}
}
That assumes you're using .NET 3.5, admittedly. Let me know if you need a .NET 2.0 solution.
Here's a LINQ-based solution which I find pleasantly compact...
var uniqueValues = myDict.GroupBy(pair => pair.Value)
.Select(group => group.First())
.ToDictionary(pair => pair.Key, pair => pair.Value);
The brute-force solution would be something like the following
var result = dictionary
.GroupBy(kvp => kvp.Value)
.ToDictionary(grp => grp.First().Value, grp.Key)
assuming you don't really care about the key used to represent a group of duplicates and it is acceptable to rebuild the dictionary.
Jon beat me to the .NET 3.5 solution, but this should work if you need a .NET 2.0 solution:
List<string> vals = new List<string>();
Dictionary<string, string> newDict = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> item in myDict)
{
if (!vals.Contains(item.Value))
{
newDict.Add(item.Key, item.Value);
vals.Add(item.Value);
}
}
foreach (var key in mydict.Keys)
tempdict[mydict[key]] = key;
foreach (var value in tempdict.Keys)
uniquedict[tempdict[value]] = value;
Dictionary<string, string> test = new Dictionary<string,string>();
test.Add("1", "blue");
test.Add("2", "blue");
test.Add("3", "green");
test.Add("4", "red");
Dictionary<string, string> test2 = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> entry in test)
{
if (!test2.ContainsValue(entry.Value))
test2.Add(entry.Key, entry.Value);
}
This is how I did it:
dictionary.add(control, "string1");
dictionary.add(control, "string1");
dictionary.add(control, "string2");
int x = 0;
for (int i = 0; i < dictionary.Count; i++)
{
if (dictionary.ElementAt(i).Value == valu)
{
x++;
}
if (x > 1)
{
dictionary.Remove(control);
}
}
In addition to the answer of Jon Skeet , if your value is an intern object you can use :
var uniqueValues = myDict.GroupBy(pair => pair.Value.Property)
.Select(group => group.First())
.ToDictionary(pair => pair.Key, pair => pair.Value);
This way you will remove the duplicate only on one property of the object
Just a footnote to those using the Revit API, this is one method that works for me in removing duplicate elements, when you can't use say wallType as your object type and instead need to leverage raw elements. it's a beaut mate.
//Add Pair.value to known values HashSet
HashSet<string> knownValues = new HashSet<string>();
Dictionary<Wall, string> uniqueValues = new Dictionary<Wall, string>();
foreach (var pair in wall_Dict)
{
if (knownValues.Add(pair.Value))
{
uniqueValues.Add(pair.Key, pair.Value);
}
}

How to update the value stored in Dictionary in C#?

How to update value for a specific key in a dictionary Dictionary<string, int>?
Just point to the dictionary at given key and assign a new value:
myDictionary[myKey] = myNewValue;
It's possible by accessing the key as index
for example:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary["test"] = 1;
dictionary["test"] += 1;
Console.WriteLine (dictionary["test"]); // will print 2
You can follow this approach:
void addOrUpdate(Dictionary<int, int> dic, int key, int newValue)
{
int val;
if (dic.TryGetValue(key, out val))
{
// yay, value exists!
dic[key] = val + newValue;
}
else
{
// darn, lets add the value
dic.Add(key, newValue);
}
}
The edge you get here is that you check and get the value of corresponding key in just 1 access to the dictionary.
If you use ContainsKey to check the existance and update the value using dic[key] = val + newValue; then you are accessing the dictionary twice.
Use LINQ: Access to dictionary for the key and change the value
Dictionary<string, int> dict = new Dictionary<string, int>();
dict = dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value + 1);
This simple check will do an upsert i.e update or create.
if(!dictionary.TryAdd(key, val))
{
dictionary[key] = val;
}
Here is a way to update by an index much like foo[x] = 9 where x is a key and 9 is the value
var views = new Dictionary<string, bool>();
foreach (var g in grantMasks)
{
string m = g.ToString();
for (int i = 0; i <= m.Length; i++)
{
views[views.ElementAt(i).Key] = m[i].Equals('1') ? true : false;
}
}
update - modify existent only. To avoid side effect of indexer use:
int val;
if (dic.TryGetValue(key, out val))
{
// key exist
dic[key] = val;
}
update or (add new if value doesn't exist in dic)
dic[key] = val;
for instance:
d["Two"] = 2; // adds to dictionary because "two" not already present
d["Two"] = 22; // updates dictionary because "two" is now present
This may work for you:
Scenario 1: primitive types
string keyToMatchInDict = "x";
int newValToAdd = 1;
Dictionary<string,int> dictToUpdate = new Dictionary<string,int>{"x",1};
if(!dictToUpdate.ContainsKey(keyToMatchInDict))
dictToUpdate.Add(keyToMatchInDict ,newValToAdd );
else
dictToUpdate[keyToMatchInDict] = newValToAdd; //or you can do operations such as ...dictToUpdate[keyToMatchInDict] += newValToAdd;
Scenario 2: The approach I used for a List as Value
int keyToMatch = 1;
AnyObject objInValueListToAdd = new AnyObject("something for the Ctor")
Dictionary<int,List<AnyObject> dictToUpdate = new Dictionary<int,List<AnyObject>(); //imagine this dict got initialized before with valid Keys and Values...
if(!dictToUpdate.ContainsKey(keyToMatch))
dictToUpdate.Add(keyToMatch,new List<AnyObject>{objInValueListToAdd});
else
dictToUpdate[keyToMatch] = objInValueListToAdd;
Hope it's useful for someone in need of help.
This extension method allows a match predicate delegate as the dictionary key selector, and a separate delegate to perform the dictionary value replacement, so it's completely open as to the type of key/value pair being used:
public static void UpdateAll<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<TKey, TValue, bool> matchPredicate, Func<TValue, TValue> updatePredicate)
{
var keys = dictionary.Keys.Where(k => matchPredicate(k, dictionary[k])).ToList();
foreach (var key in keys)
{
dictionary[key] = updatePredicate(dictionary[key]);
}
}
Example usage:
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "One");
dict.Add(2, "Two");
dict.Add(3, "Three");
//Before
foreach(var kvp in dict){
Console.WriteLine(kvp.Value);
}
dict.UpdateAll(
matchPredicate: (k, v) => k >= 2, //Update any dictionary value where the key is >= 2
updatePredicate: (v) => v = v + " is greater than One"
);
//After
foreach(var kvp in dict){
Console.WriteLine(kvp.Value);
}
You Can Also Use This Method :
Dictionary<int,int> myDic = new();
if (myDic.ContainsKey(1))
{
myDic[1] = 1234; // or use += to update it
}
Or By Value :
if (myDic.ContainsValue(1))
{
//do something ...
}

Categories