Error using a dictionary in c# - c#

I am trying to search through a dictionary to see if it has a certain value and if so then to change it.
Here is my code:
foreach (var d in dictionary)
{
if (d.Value == "red")
{
d.Value = "blue";
}
}
In visual studio when i step through the code debugging it i can see it change the value then when it hits the foreach loop to reiterate again it throws an exception
"Collection was modified; enumeration operation may not execute"
How do i fix this?

You can't change it in the middle of the foreach - you'll need to come up with some other mechanism, such as:
// Get the KeyValuePair items to change in a separate collection (list)
var pairsToChange = dictionary.Where(d => d.Value == "red").ToList();
foreach(var kvp in pairsToChange)
dictionary[kvp.Key] = "blue";

You can't modify a collection whilst you're enumerating over it (in a loop).
You'll need to add your changes to a collection, then change them separately. Something like:
var itemsToChange = dictionary
.Where(d => d.Value == "red")
.ToDictionary(d => d.Key, d => d.Value);
foreach (var item in itemsToChange)
{
dictionary[item.Key] = "blue";
}

If you want to replace all occurences of "red", you'll need to store the KeyValuePairs in a list or something like that:
var redEntries = dictionary.Where(e => e.Value == "red").ToList();
foreach (var entry in redEntries) {
dictionary[entry.Key] = "blue";
}

var dict = new Dictionary<string, string>()
{
{ "first", "green" },
{ "second", "red" },
{ "third", "blue" }
};
foreach (var key in dict.Keys.ToArray())
{
if (dict[key] == "red")
{
dict[key] = "blue";
}
}

You cannot modify the collection you are iterating over in a foreach loop. If you could do that, it would open up several problems, such as "Do I run it on this newly-added value too?"
Instead, you should do something like this:
foreach( string key in dictionary.Keys )
{
if( dictionary[key] == "red" )
{
dictionary[key] = "blue";
}
}

Objects in foreach loops are read-only.
Please read through this and this for more understanding.

Related

How to join values from dictionary?

I have dictionary code as follows:
int entry=0;
string[] numbers ={"123","123","123","456","123"};
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
foreach (string number in numbers)
{
if (dictionary.ContainsKey("ABC"))
{
}
else if (!dictionary.ContainsKey("ABC") && entry==0)
{
dictionary.Add("ABC", new List<string>());
dictionary["ABC"].Add(number);
entry = 1;
}
else if (!dictionary.ContainsKey("ABC") && entry == 1)
{
dictionary["ABC"].Add(number);
}
}
foreach(KeyValuePair<string,string> kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}", kvp.Key,kvp.Value);
}
Console.ReadKey();
I want output like as follows Key="ABC",Value="123,456" i.e. I need to print all the dictionary values only once without repeat. In above string array 123 came 4 times.But I want to print that only one time and need 456 also and also joint that values with comma(",").So I need output like Key="ABC",Value="123,456". Please share your ideas. Thanks in advance.
I need to print all the dictionary values only once without repeat.
Use Distinct method.
joint that values with comma(",")
Use String.Join method.
foreach(var kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}",
kvp.Key,
String.Join(", " kvp.Value.Distinct())
);
}
You can try like this:
foreach(var value in dictionary.Values.Distinct())
{
names = String.Join(", ", value);
}
The following for loop variable is incorrect, I think:
foreach(KeyValuePair<string,string> kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}", kvp.Key,kvp.Value);
}
It should read: then note the difference in the writeline
foreach(KeyValuePair<string,List<string>> kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}", kvp.Key,string.Join(",", kvp.Value.ToArray()));
}
You can use this simple linq to flatten and join all your dictionary contents:
var result = string.Join(" - ", dic.Select(kvp => string.Format("Key={0}, Values={1}", kvp.Key, string.Join(", ",kvp.Value.Distinct()))));
Instead of using this array :
string[] numbers = {"123","123","123","456","123"};
Add another array as :
string[] uniqueNumbers = numbers.Distinct().ToArray();
and now use this array with unique values to add to the dictionary.

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.

Compare List<string> and enable the required control

I am having two list<string> as follows
listA is having the following values 10,20,30,40 and
listB is having the following values 10,20,30
If listB contains listA elements i would like to enable particular controls if not i would like to disable the Controls
I tried of using two loops as follows
for(int ilist1=0;ilist1<listA.count;ilist1++)
{
for(int ilist2=0;ilist2<listB.count;ilist2++)
{
if(listA[ilist1]==listB[ilist2])
{
//Enable particular control
}
}
}
But i know this is not an appropriate one to do so can any one tell me the best approach to achieve this
What you want to do is to hash the items in the first list into a set then verify for each item in the second is within the set. Unfortunately the HashSet<> is not available so the closest you can get is the Dictionary<,>.
Do this:
Dictionary<string, string> set = new Dictionary<string, string>();
foreach (string item in listA)
{
set.Add(item, item);
}
foreach (string item in listB)
{
if (!set.ContainsKey(item))
{
//Enable particular control
}
}
It's easy by using the Intersect method:
if (listB.Intersect(listA).Count() > 0)
{
//enable Control
}
else
{
//disable control
}
I think you are looking for something like this
List<string> lista = new List<string>() {"10","40","30" };
List<string> listb = new List<string>() { "10", "20" };
var diff = listb.Except<string>(lista);
diff should give you the ones which didn't match else all would have been matched.
For 2.0
if (listb.TrueForAll(delegate(string s2) { return lista.Contains(s2); }))
MessageBox.Show("All Matched");
else
MessageBox.Show("Not Matched");
In fx 2.0, you can do it like this:
string b = listA.Find(delegate(string a) { return listB.Contains(a); });
if (string.IsNullOrEmpty(b))
{
//disable control
}
else
{
//enable control
}
Control.Enabled = listB.Intersect(listA).Any()
Note that Any() will only check to see if there is at least one item. Count() > 0 will evaluate the entire collection when you only need to check if there is at least one item
Edit: If you are in a .NET 2.0 environment then you can loop through and do this:
foreach (int item in listB)
{
if (listA.Contains(item))
return true;
}
return false;

Compare Dictionary<string,List<object>>

I am comparing two dictionary(dic1 and dic2) with rule that get values from dic2 where key match but values does not match or key is missing in dic2.
Don’t need to iterate through dic2 for missing/different values in dic1.
Below code is working ok I would like to know is there any better way using .NET 2.0 (NO LINQ) .
if optimization is require which option is better?
Dictionary<string,List<foo>> dic1 = new Dictionary<string,List<foo>>();
Dictionary<string,List<foo>> dic2 = new Dictionary<string,List<foo>>();
dic1.add("1", new foo("a"));
dic1.add("2", new foo("b"));
dic1.add("3", new foo("c"));
dic1.add("3", new foo("c1"));
dic1.add("4", new foo("d"));
dic2.add("1", new foo("a"));
dic2.add("2", new foo("b1"));
dic2.add("3", new foo("c"));
dic2.add("3", new foo("c2"));
//I write code which allow duplicate key in dictionary
Option 1
foreach (KeyValuePair<string, List<foo>> var in dic1)
{
if (dic2.ContainsKey(var.Key))
{
List<foo> tempList = var.Value.FindAll(delegate(foo s)
{
return !dic2[var.Key].Contains(s);
});
result.AddRange(tempList);
}
else
{
result.Add(var.Value);
}
}
Option 2
List<string> list1key = new List<string>(dic1.Keys);
list1key.ForEach(delegate(string key)
{
if (dic2.ContainsKey(key))
{
List<foo> tempList = dic1[key].FindAll(delegate(foos)
{
return !dic2[key].Contains(s);
});
result.AddRange(tempList);
}
else
{
result.AddRange(dic1[key]);
}
});
You can speed things up with either option if you use TryGetValue when accessing dic2, so you only have to do a key lookup once.
Your first option looks simpler and possibly faster, i'd go with that.
Cheers
I would use Option 1. Here's a variation on it using TryGetValue instead of looking up dic2[var.Key] so many times:
foreach (KeyValuePair<string, List<foo>> var in dic1)
{
List<foo> dic2val;
if (dic2.TryGetValue(var.Key, out dic2val))
{
List<foo> tempList = var.Value.FindAll(delegate(foo s)
{
return !dic2val.Contains(s);
});
result.AddRange(tempList);
}
else
{
result.Add(var.Value);
}
}

What's the pattern to use for iterating over associated sets of values?

It's pretty common - especially as you try to make your code become more data-driven - to need to iterate over associated collections. For instance, I just finished writing a piece of code that looks like this:
string[] entTypes = {"DOC", "CON", "BAL"};
string[] dateFields = {"DocDate", "ConUserDate", "BalDate"};
Debug.Assert(entTypes.Length == dateFields.Length);
for (int i=0; i<entTypes.Length; i++)
{
string entType = entTypes[i];
string dateField = dateFields[i];
// do stuff with the associated entType and dateField
}
In Python, I'd write something like:
items = [("DOC", "DocDate"), ("CON", "ConUserDate"), ("BAL", "BalDate")]
for (entType, dateField) in items:
# do stuff with the associated entType and dateField
I don't need to declare parallel arrays, I don't need to assert that my arrays are the same length, I don't need to use an index to get the items out.
I feel like there's a way of doing this in C# using LINQ, but I can't figure out what it might be. Is there some easy method of iterating across multiple associated collections?
Edit:
This is a little better, I think - at least, in the case where I have the luxury of zipping the collections manually at declaration, and where all the collections contain objects of the same type:
List<string[]> items = new List<string[]>
{
new [] {"DOC", "DocDate"},
new [] {"CON", "ConUserDate"},
new [] {"SCH", "SchDate"}
};
foreach (string[] item in items)
{
Debug.Assert(item.Length == 2);
string entType = item[0];
string dateField = item[1];
// do stuff with the associated entType and dateField
}
In .NET 4.0 they're adding a "Zip" extension method to IEnumerable, so your code could look something like:
foreach (var item in entTypes.Zip(dateFields,
(entType, dateField) => new { entType, dateField }))
{
// do stuff with item.entType and item.dateField
}
For now I think the easiest thing to do is leave it as a for loop. There are tricks whereby you can reference the "other" array (by using the overload of Select() that provides an index, for example) but none of them are as clean as a simple for iterator.
Here's a blog post about Zip as well as a way to implement it yourself. Should get you going in the meantime.
Create a struct?
struct Item
{
string entityType;
string dateField;
}
Pretty much the same as your Pythonic solution, except type-safe.
This is realy a variation on the other themes, but this would do the trick also...
var items = new[]
{
new { entType = "DOC", dataField = "DocDate" },
new { entType = "CON", dataField = "ConUserData" },
new { entType = "BAL", dataField = "BalDate" }
};
foreach (var item in items)
{
// do stuff with your items
Console.WriteLine("entType: {0}, dataField {1}", item.entType, item.dataField);
}
You can use the pair and a generic List.
List<Pair> list = new List<Pair>();
list.Add(new Pair("DOC", "DocDate"));
list.Add(new Pair("CON", "ConUserDate"));
list.Add(new Pair("BAL", "BalDate"));
foreach (var item in list)
{
string entType = item.First as string;
string dateField = item.Second as string;
// DO STUFF
}
Pair is part of the Web.UI, but you can easily create your own custom class or struct.
If you just want to declare the lists inline, you can do that in one step:
var entities = new Dictionary<string, string>() {
{ "DOC", "DocDate" },
{ "CON", "ConUserDate" },
{ "BAL", "BalDate" },
};
foreach (var kvp in entities) {
// do stuff with kvp.Key and kvp.Value
}
If they're coming from other things, we have a bunch of extension methods to build dictionaries from various data structures.

Categories

Resources