Looping through dictionary object - c#

I am very new to .NET, used to working in PHP. I need to iterate via foreach through a dictionary of objects. My setup is an MVC4 app.
The Model looks like this:
public class TestModels
{
Dictionary<int, dynamic> sp = new Dictionary<int, dynamic>
{
{1, new {name="abc", age="1"}},
{2, new {name="def", age="2"}}
}
}
Controller:
public class TestController : Controller
{
Models.TestModels obj = new Models.TestModels();
}
How do I loop through the obj object and retrieve the values of the dictionary and print them in the view?

One way is to loop through the keys of the dictionary, which I recommend:
foreach(int key in sp.Keys)
dynamic value = sp[key];
Another way, is to loop through the dictionary as a sequence of pairs:
foreach(KeyValuePair<int, dynamic> pair in sp)
{
int key = pair.Key;
dynamic value = pair.Value;
}
I recommend the first approach, because you can have more control over the order of items retrieved if you decorate the Keys property with proper LINQ statements, e.g., sp.Keys.OrderBy(x => x) helps you retrieve the items in ascending order of the key. Note that Dictionary uses a hash table data structure internally, therefore if you use the second method the order of items is not easily predictable.
Update (01 Dec 2016): replaced vars with actual types to make the answer more clear.

It depends on what you are after in the Dictionary
Models.TestModels obj = new Models.TestModels();
foreach (var keyValuPair in obj.sp)
{
// KeyValuePair<int, dynamic>
}
foreach (var key in obj.sp.Keys)
{
// Int
}
foreach (var value in obj.sp.Values)
{
// dynamic
}

You can do it like this.
Models.TestModels obj = new Models.TestModels();
foreach (var item in obj.sp)
{
Console.Write(item.Key);
Console.Write(item.Value.name);
Console.Write(item.Value.age);
}
The problem you most likely have right now is that the collection is private. If you add public to the beginning of this line
Dictionary<int, dynamic> sp = new Dictionary<int, dynamic>
You should be able to access it from the function inside your controller.
Edit: Adding functional example of the full TestModels implementation.
Your TestModels class should look something like this.
public class TestModels
{
public Dictionary<int, dynamic> sp = new Dictionary<int, dynamic>();
public TestModels()
{
sp.Add(0, new {name="Test One", age=5});
sp.Add(1, new {name="Test Two", age=7});
}
}
You probably want to read up on the dynamic keyword as well.

public class TestModels
{
public Dictionary<int, dynamic> sp = new Dictionary<int, dynamic>();
public TestModels()
{
sp.Add(0, new {name="Test One", age=5});
sp.Add(1, new {name="Test Two", age=7});
}
}

Related

how to get corresponding "Name"

I have a C# dictionary in which I have a corresponding NAME against the ID.
Dictionary<string, List<object>> dict = new Dictionary<string, List<object>>
{
{ "ID", new List<object> { "Id1", "Id2" } },
{ "NAME", new List<object> { "True", "False" } }
};
foreach (var id in dict["ID"])
{
Console.WriteLine(id);
//how to get corresponding "Name". For "Id1" = "True" and for "Id2" = "False"
}
In above code I loop through ID, but how to get corresponding NAME?
I think a better design would be to create a class with the two properties and then iterate. If you find yourself having to sync different data structures for simple data representations then I'd suggest rethinking the design.
public class MyClass
{
public string Id { get; set; }
public bool Name { get; set; }
}
And then hold a List<MyClass> which when you iterate:
foreach (var item in list)
{
// Now access item.Id, item.Name
}
The use of dictionaries is good when you have some sort of natural key for your data and you want to access access an item by that key. As the items are accessed via a hash function accessing by key is done in O(1) whereas searching in a list is O(n). However in your case you are iterating all items in any case so no need for dictionary and arranging the data in a class is a better design.
A bit about the differences and some references:
what is the difference between list<> and dictionary<> in c#
List vs ArrayList vs Dictionary vs Hashtable vs Stack vs Queue?
If you do have control over dictionary data it's best to either use Gilad's answer and store everything in List<MyClass> or to use Dictionary<string, bool> :
Dictionary<string, bool> dict = new Dictionary<string, bool>()
{
{ "Id1", true }, { "Id2", false },
};
But if you do not have control over format of this data and get it as a dictionary from somewhere (for example web service) you could utilize .Zip method to convert this dictionary into one list of either anonymous objects/custom class or Tuples, where Item1 is Id and Item2 is value:
// anonymous object
var data = dict["ID"].Zip(dict["NAME"], (x, y) => new
{
ID = x,
NAME = y
}).ToList();
// tuple
// List<Tuple<object, object>> data = dict["ID"].Zip(dict["NAME"], Tuple.Create).ToList();
foreach (var obj in data)
{
Console.WriteLine(obj.ID + " " obj.NAME);
}
The other answers are probably what you should do to better structure your code. However, if you need to stick to your original use case, you could do something like this:
//Depending on what you're dealing with: Dictionary<string, List<string>>
Dictionary<string, List<object>> dict = new Dictionary<string, List<object>>{
{"ID", new List<object>{"Id1", "Id2"}},
{"NAME", new List<object>{"True", "False"}}
};
foreach(var v in dict.Keys){
Console.WriteLine($"{v} = {string.Join(",", dict[v])}");
}
//Output:
//ID = Id1,Id2
//NAME = True,False
Even if you have the just the mapping of ID and Name you can have very simple variable
Dictionary<string,string> lookup = new Dictionary<string,string>();
lookup.Add("ID1","True")
and if Name is Boolean type then replace string to bool in the
Dictionary<string,bool> lookup = new Dictionary<string,bool>();

ExpandoObject contains no public properties only in VS2013

I am trying to deserialize my JSON object and pass it as a model to my view. Since I don't know what properties the model will have, I have read that I should use an ExpandoObject.
Here is what I have tried:
public ActionResult Index()
{
var myObj = new object();
List<Dictionary<string, object>> container = new List<Dictionary<string, object>>()
{
new Dictionary<string, object> { { "Text", "Hello world" } }
};
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
myObj = json_serializer.DeserializeObject(json_serializer.Serialize(container));
return View(myObj.ToExpando());
}
And, in the same namespace I have defined this class:
public static class Helpers
{
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in anonymousDictionary)
expando.Add(item);
return (ExpandoObject)expando;
}
}
And, in my view I have this loop:
#foreach (var item in Model)
{
#item.Text
}
When I run, I get this error:
'System.Collections.Generic.KeyValuePair' does not
contain a definition for 'Text'
Upon debugging, the Model doesn't seem to have any public properties. When I look deep within the private members, I see the data that I want.
Why aren't these public properties such that I can access them?
Edit: Here you can see the expando object model that is getting passed to my view:
Note: The SyncRoot property seems to contain my object.
Edit: This is the deserialized object:
Notice that #item is defined as a System.Collections.Generic.KeyValuePair based on your error.
These means that you have two properties: Key and Value.
Here are two possible solution:
#foreach (var item in Model.Values)
{
#item.Id
}
or
#foreach (var item in Model)
{
#item.Value.Id
}
The solution for me was to do something like this (using the ExpandoObjectConverter):
var myObj = new object();
List<Dictionary<string, object>> container = new List<Dictionary<string, object>>()
{
new Dictionary<string, object> { { "Text", "Hello world" } }
};
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
var converter = new ExpandoObjectConverter();
var obj = JsonConvert.DeserializeObject<IEnumerable<ExpandoObject>>(json_serializer.Serialize(container), converter);
return View(obj);
However, this doesn't account for deeply nested JSON objects. I can probably create some sort of recursive method.
It's sad that the framework doesn't support such an obvious requirement; unless I am missing something.

Automapper Update Dictionary Values

I have an Entity that contains a dictionary, and what i want to achieve is that automapper not simply Replace the dictionary but updates it's values.
class ExampleClass
{
public string Name { get; set; }
public Dictionary<int, string[]> Dictionary { get; set; }
}
Mapper.CreateMap<ExampleClass, ExampleClass>().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
var originalClass = new ExampleClass();
originalClass.Name = "Original Class";
originalClass.Dictionary = new Dictionary<int, string[]>
{
{0, new []{"V1", "V2", "V3"}},
{1, new []{"V1", "V2", "V3"}},
{2, new []{"V1", "V2", "V3"}}
};
var newelyCreatedClass = new ExampleClass();
newelyCreatedClass.Dictionary = new Dictionary<int, string[]>
{
{1, new []{"E1", "E2", "E9"}},
};
Mapper.Map(newelyCreatedClass, originalClass);
In the above code, automapper strangely doesn't update the Dictionary element with key == 1 but replaces the whole original one with the one created in newelyCreatedClass .
AutoMapper just automatically compares and sets values if they exist, this is why the property is getting overwritten. But what you can do is use an automapper feature called Custom Value Resolvers.
Then you could just write a resolver to check the dictionary and its values.
public class CustomResolver : IValueResolver<ExampleClass, ExampleClass, Dictionary<int, string[]>>
{
public Dictionary<int, string[]> Resolve(ExampleClass source, ExampleClass destination, Dictionary<int, string[]> member, ResolutionContext context)
{
// logic to iterate through the dictionarys and resolve into dictionary containing values that you want.
}
}

Updating Dictionary C#

I've a problem with updating a dictionary
I also have read many topics about this saying all the same (e.g. Link)
ExampleDict[key] = value;
I was trying this to my own code:
Model:
public Dictionary<int, string> Info { get; set; }
public Dictionary<int, string> GetInfo(int id)
{
Info = new Dictionary<int, string>();
var game = db.Games.Find(id);
var playerOne = db.Players.Find(game.PlayerOneId);
var playerTwo = db.Players.Find(game.PlayerTwoId);
var PlayerOneName = playerOne.Nickname;
var PlayerTwoName = playerTwo.Nickname;
int scoreOne = CountScorePlayerOne();
int scoreTwo = CountScorePlayerTwo();
// old aproach:
Info.Add(scoreOne, PlayerOneName);
Info.Add(scoreTwo, PlayerTwoName);
//new approach
Info[key] = scoreOne;
return Info;
}
Error
The name 'key' does not exist in the current context
Note: I'm a student and this is for a school project.
Any ideas on what I am doing wrong?
Solved through the code sample from Jon Senchyna, Thank you!
It appears that you are never declaring the variable key. You probably did not mean to use "key" in the "new approach" line.
In addition, I believe your Dictionary is backwards, as it looks like the player name should be the key, not their score. The way you are currently declaring it (Dictionary<int, string>), you are creating a dictionary whose keys are int (score?) and whose values are string (name?).
Here are my suggested edits:
// Corrected dictionary definitions
public Dictionary<string, int> Info { get; set; }
public Dictionary<string, int> GetInfo(int id)
{
// You may want to use a local variable here instead
Info = new Dictionary<string, int>();
...
Info[PlayerOneName] = scoreOne;
Info[PlayerTwoName] = scoreTwo;
return Info;
}
Here are some useful links for learning more about using the Dictionary class (and C# in general if you browse around a bit):
MSDN
DotNetPearls
In the example link in your question there's the method:
public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
Which has a string key as an argument. You need to define that key, too.

How to copy list of dictionaries

I have two dictionaries. When I change a value in dictionary 1, the same change appears in dictionary 2. How do I change a value only in dictionary 1, not in dictionary 2 as well?
List<Dictionary<string, string>> ld1 = new List<Dictionary<string, string>>();
Dictionary<string, string> d1 = new Dictionary<string,string>();
d1.Add("Text", "Value1");
d1.Add("Format", "Value2");
ld1.Add(d1);
List<Dictionary<string, string>> ld2 = new List<Dictionary<string, string>>(ld1);
// ld2 = ld1
ld1[0]["Text"] = "Eulav"; // should: change only in the first dictionary
// actually: changes in the second dictionary as well
Console.WriteLine(ld1[0]["Text"]);
Console.WriteLine(ld2[0]["Text"]);
Outputs
Eulav
Eulav
You only create a new list but the items in that list reference the same objects (dictionaries), so you need to create a copy of each item as well:
var ld2 = new List<Dictionary<string, string>>();
foreach (var dict in ld1)
{
ld2.Add(new Dictionary<string, string>(dict));
}
If you want to have two shallow copies of a particular Dictionary<TKey, TValue> then just use the constructor to create a copy
Dictionary<string, string> ld1 = ...;
Dictionary<string, string> ld2 = new Dictionary<string, string>(ld1);
Note: In this particular case it will be a deep copy since string is immutable and has no child data which needs to be deeply copied
The point to remember here is that though you are creating two instances (Two distinct memory allocations) of List, you are only creating "one" instance of Dictionary.
Thus, both the lists have the same memory pointer, pointing to the same dictionary. And it is obvious that the change in one will update the other too.
As suggested by others, here you need to create one more instance of Dictinary (A distinct memory allocation) and copy the values of the first one to it.
Dictionary<string, string> ld2 = new Dictionary<string, string>(ld1);
Doing this will store different instances in list and changes in one will not effect other.
user1158781 in order do it with non inmutable objects like strings, you will have to clone every element of the dictionary to a new one.
You can implement the IClonable interface. I leave a litle example:
class Program
{
static void Main(string[] args)
{
Dictionary<int, Person> dic1 = new Dictionary<int, Person>();
dic1.Add(0, new Person { Name = "user1158781" });
Dictionary<int, Person> dic2 = new Dictionary<int, Person>();
foreach (var item in dic1)
{
dic2.Add(item.Key, (Person)item.Value.Clone());
}
dic1[0].Name = "gz";
Console.WriteLine(dic1[0].Name);
Console.WriteLine(dic2[0].Name);
}
class Person : ICloneable
{
public string Name { get; set; }
public object Clone()
{
return new Person { Name = this.Name };
}
}
}

Categories