I have the following dictionary.
Dictionary<string, List<string>> dictSubjects = new Dictionary<string, List<string>>();
and I am trying to get rid of potential duplicates residing within each list instace of the respective dictionary entry.
This is what I have tried but get and error along the lines of the list being read only
foreach (var kvp in dictSubjects)
{
lstSubjectsNoDupes.Clear();
for (int i = kvp.Value.Count - 1; i >= 0; i--)
{
if(lstSubjectsNoDupes.Contains(kvp.Value[i]))
{
lstSubjectsNoDupes.Add(kvp.Value[i]);
}
}
kvp.Value = lstSubjectsNoDupes;
}
How can I effectively get rid of potential duplicates within each list of my Dictionary?
The simplest way if you don't care too much about efficiency would be:
dictSubjects = dictSubjects.ToDictionary(pair => pair.Key,
pair => pair.Value.Distinct().ToList());
Alternatively, to update the existing dictionary:
foreach (var key in dictSubjects.Keys.ToList())
{
dictSubjects[key] = dictSubjects[key].Distinct().ToList();
}
Note the use of ToList here to avoid iterating over a view of a collection which is being modified. Without this, InvalidOperationException is thrown.
What about
foreach (var kvp in dictSubjects.ToList())
dictSubjects[kvp.Key] = kvp.Value.Distinct().ToList();
Related
I want to change all the values that fulfill a certain criterium in a C# dictionary.
Simply editing the values like this
foreach (var kv in dictionary)
{
kv.Value += 1;
}
does not work because the KeyValuePair of the foreach loop is read only.
However, editing the entries directly like this:
foreach (var kv in dictionary)
{
dictionary[kv.Key] = kv.Value + 1;
}
also doesn't work, because it modifies the collection and breaks the iterator.
At this point, the only remaining solution I can think of is storing all keys of the dictionary in a list, and then using that to edit the values during a second loop, however, that seems like a pretty inelegant solution to me.
Is there any better alternative?
You could create an array (or a List with .ToList()) from the .Keys in the foreach, something like this:
foreach (string key in dictionary.Keys.ToArray())
{
dictionary[key] += 1;
}
You can use ToDictionary to create new Dictionary and change the origin in the loop, like :
foreach (var kv in dictionary.ToDictionary(k=>k.Key,v=>v.Value))
{
dictionary[kv.Key] = kv.Value + 1;
}
I hope you find this helpful.
I have an outer loop iterating over an array of substrings to be matched in the dictionary. In the inner loop I want to iterate over the dictionary and delete an entry whose key contains a substring.How to do this without getting "Collection was modified Exception"?
foreach (string outerKey in new string[] { "PAYERADDR_PAYERNAME", "RECADDR_RECNAME", "PAYERADDR_ADDR", "RECADDR_ADDR" })
{
foreach (var item in _generalWorksheetData.Where(kvp => kvp.Value.Contains(outerKey)).ToList())
{
_generalWorksheetData.Remove(item.Key);
}
}
You need a new collection:
List<string> todelete = dictionary.Keys.Where(k => k.Contains("substring")).ToList();
todelete.ForEach(k => dictionary.Remove(k));
or with a foreach:
foreach (string key in todelete)
dictionary.Remove(key); // safe to delete since it's a different collection
If Dictionary.Keys implemented IList instead of just ICollection you could access it in a backwards for-loop to remove them. But since there is no indexer you can't.
AFAIK, you can't. However you can store those pairs in a list and delete them in a separate loop from the first.
Just update your inner foreach as following:
foreach (var item in _generalWorksheetData.Keys.Where(kvp => kvp.Contains(outerKey)).ToList())
{
_generalWorksheetData.Remove(item);
}
Note that LINQ extension methods ToList and ToArray do allow you to modify collections.
List<string> sampleList = new List<string>();
sampleList.Add("1");
sampleList.Add("2");
sampleList.Add("3");
sampleList.Add("4");
sampleList.Add("5");
// Will not work
foreach (string item in sampleList)
{
sampleList.Remove(item);
}
// Will work
foreach (string item in sampleList.ToList())
{
sampleList.Remove(item);
}
Find match and remove the entries as below
var keysWithMatchingValues = dictionary.Where(d => d.Key.Contains("xyz"))
.Select(kvp => kvp.Key).ToList();
foreach(var key in keysWithMatchingValues)
dictionary.Remove(key);
I thought it would have been relatively straightforward, I am here first runing this code that uses a 3rd party software to return a set of values as a dictionary:
List<Dictionary<string, long>> result = 3rdPartyConnection.GetPlans(id, params);
I then try to loop these results (so I can populate a viewmodel with them and other values) using the following code, first I declare a new list using the viewmodel, then I loop through the results to populate the model:
List<OptionViewModel> AvailableOptions = new List<OptionViewModel>();
foreach (KeyValuePair<string, long> item in result)
{
OptionViewModel c = new OptionViewModel();
c.Code = item.Key;
c.Value = item.Value;
AvailableOptions.Add(c);
}
But it only generates the following error:
Error 257 Cannot convert type 'System.Collections.Generic.Dictionary<string,long>' to 'System.Collections.Generic.KeyValuePair<string,long>'
I don't understand what the problem is, from what I've read on c# this is how you loop through a dictionary. I have a feeling this is a simple oversight of some kind on my part....
It is a List<> of dictionaries, not a single Dictionary<,>. Use two foreach loops inside each other.
Sometimes it is better to use var in foreach loops: foreach (var item in ...) It helps you figure out what the iteration variable type is, without introducing a cast.
You will need to iterate through the List first, going through each dictionary, at which point you can then iterate through the key-value pairs:
foreach (Dictionary<string, long> dic in result)
{
foreach(KeyValuePair<string, long> item in dic)
{
OptionViewModel c = new OptionViewModel();
c.Code = item.Key;
c.Value = item.Value;
AvailableOptions.Add(c);
}
}
I am trying to update the contents of a C# Dictionary in a foreach loop, when a certain condition is met.
foreach (KeyValuePair<int, Corpus_22_04_2014_StreetTable_Row> entry in id_StreetNameDictionary)
{
if(something_happens())
{
Corpus_22_04_2014_StreetTable_Row r = entry.Value;
//Modify r
id_StreetNameDictionary[entry.Key] = r;
}
}
This throws an InvalidOperationException stating that "Collection was modified; enumeration operation may not execute.". It seems that we are not allowed to modify the contents of a Dictionary in foreach loop.
What can be a possible workaround to that?
You can simply use ToList on the dictionary to copy each key-value pair into a list. Then iterate over that list instead of Dictionary:
foreach (var entry in id_StreetNameDictionary.ToList())
{
if(something_happens())
{
Corpus_22_04_2014_StreetTable_Row r = entry.Value;
//Modify r
id_StreetNameDictionary[entry.Key] = r;
}
}
Create a list of all the keys and iterate that. For example:
foreach (var key in id_StreetNameDictionary.Keys.ToList())
{
if(something_happens())
{
var r = id_StreetNameDictionary[key];
//Modify r
id_StreetNameDictionary[key] = r;
}
}
This will be somewhat more memory efficient than creating a list of KeyValuePair structures from the dictionary.
Since it appears you really want to modify the row and not necessarily the Dictionary, then do so directly:
foreach (var entry in id_StreetNameDictionary)
{
if (something_happens())
{
((Corpus_22_04_2014_StreetTable_Row)entry.Value)["FieldToChange"] = newValue;
//...repeat for each field to change...you will be altering the row directly, no need to reassign it
}
}
Well I use the following workaround. Not very efficient maybe, but it does the work.
I declare three dictionaries:
Dictionary<int, Corpus_22_04_2014_StreetTable_Row> id_StreetNameDictionary = new Dictionary<int, Corpus_22_04_2014_StreetTable_Row>();
Dictionary<int, Corpus_22_04_2014_StreetTable_Row> tempDictionary = new Dictionary<int, Corpus_22_04_2014_StreetTable_Row>();
Dictionary<int, Corpus_22_04_2014_StreetTable_Row> swapBuffer;
I completely dump the old dictionary, with all modified and unmodified key/value pairs, into the tempDictionary. Then I swap both dictionaries and clear the unused one:
foreach (var entry in id_StreetNameDictionary)
{
Corpus_22_04_2014_StreetTable_Row row = id_StreetNameDictionary[entry.Key];
if (something_happens())
{
//Modify row
}
tempDictionary.Add(row.id, row);
}
swapBuffer = tempDictionary;
tempDictionary = id_StreetNameDictionary;
id_StreetNameDictionary = swapBuffer;
tempDictionary.Clear();
how to change Dictionary's value when enumerate it?
the following code doesn't work, because we can not change dictionary's value when enumerating it. Is there any way to get around it? Or NO WAY? Thanks
foreach (KeyValuePair<string, int> kvp in mydictionary)
{
if (otherdictionary.ContainsKey(kvp.Key))
{
mydictionary[kvp.Key] = otherdictionary[kvp.Key];
}
else
{
otherdictionary[kvp.Key] = mydictionary[kvp.Key];
}
}
The simplest way would be to take a copy first. As you only want the key value pairs, you might as well put them in a list rather than building a new dictionary though. Also, you can avoid doing quite as many lookups using TryGetValue.
var copy = myDictionary.ToList();
foreach (KeyValuePair<string, int> kvp in copy)
{
int otherValue;
if (otherdictionary.TryGetValue(kvp.Key, out otherValue))
{
mydictionary[kvp.Key] = otherValue;
}
else
{
otherdictionary[kvp.Key] = kvp.Value;
}
}
Make a copy of the values you need to enumerate over before you enumerate over them, then you can change the original source.
Since you don't actually use the value, you can change the code to this:
foreach (string key in mydictionary.Keys.ToArray())
if (otherdictionary.ContainsKey(key))
mydictionary[key] = otherdictionary[key];
else
otherdictionary[key] = mydictionary[key];
Note the use of .ToArray() there to make a temporary array copy of the key collection. This is now separate from the source dictionary, so you can change the dictionary all you want.
another option, copy the keys collection to an array and use it in for each loop -
string[] arr1 = new string[mydictionary.Count];
mydictionary.Keys.CopyTo(arr1,0);
foreach (string j in arr1)
{
if (otherdictionary.ContainsKey(j))
{
mydictionary[j] = otherdictionary[j];
}
else
{
otherdictionary[j] = mydictionary[j];
}
}