How to iterate through nested Dictionary<string, object>? - c#

I have a JSON file that I need to deserialize using the class System.Web.Script.Serialization. The following code:
string json = File.ReadAllText(#"C:\file.json");
JavaScriptSerializer ser = new JavaScriptSerializer();
var dict = ser.Deserialize<Dictionary<string, object>>(json);
creates a nested dictionary, something like this:
Dictionary<string, Object> outerDictionary;
Dictionary<string, Object> middleDictionary;
Dictionary<string, string> innerDictionary;
I now need to grab some of the values from the innerDictionary into a C# object class, like:
public class Location
{
public string Id { get; set; }
public string Name { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
So my question is, how can I iterate over the nested disctionary to get the values I need at the innermost level?
UPDATE
With the help of Jonesopolis I now have the correct loop structure, but I am still unable to get the values from the innermost dictionary?
foreach (var outer in dict)
{
foreach (var middle in (Dictionary<string, object>)outer.Value)
{
foreach (var inner in (ArrayList)middle.Value)
{
foreach (var loc in (Dictionary<string, object>)inner)
{
}
}
}
}

If you don't like the nested foreach in Jonesopolis's answer, then you can use LINQ this way:
var data = from outer in dict
from middle in (Dictionary<string, object>) outer.Value
from inner in (Dictionary<string, string>) middle.Value
select new { outer, middle, inner };
foreach (var item in data) {
// do things with item.inner
}

if you really want to work with those objects:
foreach(var outer in dict)
{
foreach (var middle in (Dictionary<string, object>) outer.Value)
{
foreach (var inner in (Dictionary<string, string>) middle.Value)
{
var location = new Location();
location.Id = inner["Id"];
//etc..
}
}
}
though, it would be much better to create a class structure that you can deserialize your json to, that accurately represents your data, instead of casting Dictionaries.

Related

Create a Dictionary from another Dictionary and a List<T> on a matching values

I have the following function, which takes a Dictionary and a List, matches rows in each of those and returns another Dictionary based on matcing items.
Is there a better way (code and performance -wise) to achieve the same result?
public sealed class ProdIds
{
public List<ProdID> Items { get; set; }
}
public sealed class ProdID
{
public string SpecialId { get; set; }
public int ItemId { get; set; }
}
Simplified view of the entries:
names: {100, "Name1"}, {333, "Name3"}, {212, "Name55"}, {99, "NameABC"}, ...
ids: {"SP44", 212}, {"SP33", 333}, {"SP11", 100}, {"SP9", 99}, ...
private static Dictionary<string, string> CreateMatchedDictionary (IReadOnlyDictionary<int, string> names, List<ProdIds> ids)
{
var dic = new Dictionary<string, string>();
foreach (var name in names)
{
foreach (var id in ids)
{
if (name.Key == id.Items[0].ItemId)
{
dic.Add(id.Items[0].SpecialId, name.Value);
}
}
}
return dic;
}
What I want to be returned here, is a new Dictionary which would look similar to this:
dic: {"SP44", "Name55"}, {"SP33", "Name3"}, {"SP11", "Name1"}, {"SP9", "NameABC"}, ...
The main performance problem is that you're looping through the names dictionary instead of taking advantage of the built-in O(1) lookup:
private static Dictionary<string, string> CreateMatchedDictionary (IReadOnlyDictionary<int, string> names, List<ProdIds> ids)
{
var dic = new Dictionary<string, string>();
foreach (var id in ids)
{
string name = null;
if (names.TryGetValue(id.Items[0].ItemId, out name)
{
dic.Add(id.Items[0].SpecialId, name);
}
}
return dic;
}
You could use Linq to make the code more concise, but it's not going to improve performance and might make debugging harder.

Json.Net Is it faster to deserialize to JObject or Dictionary?

I'm trying to model a Json for deserialization where one of the properties is an object with a long list of keys and values.
{
"key1": "value1",
"key2": "value2",
//this guy
"longlist": {
"6060": 123,
"6061": 664,
...
"6200": 43
}
}
In my application, I don't need to look inside longlist, I only want to be able to append one longlist to another.
Is it better for me to model longlist as a Dictionary<string, int> or as a JObject, considering the performance of deserialization for each?
edit: order of keys in longlist doesn't matter.
public class RootObject
{
public string key1 { get; set; }
public string key2 { get; set; }
public Dictionary<string, int> longlist { get; set; }
}
JObject jsonResponse = JObject.Parse(r);
JObject objResponse = (JObject)jsonResponse["longlist"];
RootObject _Data = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(jsonResponse.ToString());
foreach (KeyValuePair<string, int> kvp in _Data.longlist)
{
Console.WriteLine(string.Format("Key: {0} Value: {1}", kvp.Key, kvp.Value));
}
fiddle: https://dotnetfiddle.net/9ZyKwN

map entity to runtime created dto

Is there an automagic (automapper?) way to map an entity to a runtime created dynamic object with properties passed as parameters? I want to do an API where the clients can select the properties of the entities they want to fetch.
I mean:
class Patient
{
public int PatientId{ get; set; }
public string Name{ get; set; }
public string LastName{ get; set; }
public string Address{ get; set; }
...
}
getPatient(string[] properties)
{
//Return an object that has the properties passed as parameters
}
Imagine you only want to fetch a PatientDTO with PatientId and Name:
getPatient(new string[]{"PatientId", "Name"}
should return
{
"PatientId": "1234",
"Name": "Martin",
}
and so on.
For now I'm doing it with Dictionary, but probably there is a better way. This is my approach:
For a single object:
public static Dictionary<string, object> getDTO(string[] properties, T entity)
{
var dto = new Dictionary<string, object>();
foreach (string s in properties)
{
dto.Add(s, typeof(T).GetProperty(s).GetValue(entity));
}
return dto;
}
For a list of objects:
public static List<Dictionary<string, object>> getDTOList(string[] properties, List<T> TList)
{
var dtoList = new List<Dictionary<string, object>>();
foreach(T entity in TList)
{
dtoList.Add(getDTO(properties, entity));
}
return dtoList;
}
Thank you.
How about creating a new dynamic object based solely on the specified property fields and returning the dynamic?
You will need to add using statements for: System.Dynamic and System.ComponentModel for the following to work.
public static dynamic getDTO(object entity, string[] properties)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var p in properties)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(entity.GetType()))
{
if (property.Name == p)
{
expando.Add(p, property.GetValue(entity));
break;
}
}
}
return expando as ExpandoObject;
}
Calling this method would look something like this:
var patient = new Patient() { PatientId = 1, Name = "Joe", LastName = "Smith", Address = "123 Some Street\nIn Some Town, FL 32333" };
var propList = new string[] { "PatientId", "Name", "Address" };
dynamic result = getDTO(patient, propList);
Console.WriteLine("Id:{0} Name: {1}\nAddress: {2}", result.PatientId, result.Name, result.Address);
Console.ReadLine();

C# - How to parse json

I have a json string as following
string json = "{\"Method\":\"LOGIN\",\"Skill\":{\"1\":\"SKILL-1\",\"2\":\"SKILL-2\"}}";
I am using JavaScriptSerializer to parse json
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
var dict = oSerializer.Deserialize<Dictionary<string,object>>(json);
I am getting Method = LOGIN using following line
MessageBox.Show("Method = "+dict["Method"].ToString());
But how to get Skill in a loop. like
Skill
1 = SKILL-1
2 = SKILL-2
The value mapping to your Skill key is actually another Dictionary<string, object>. You can iterate it by casting the object:
string json = "{\"Method\":\"LOGIN\",\"Skill\":{\"1\":\"SKILL-1\",\"2\":\"SKILL-2\"}}";
var oSerializer = new JavaScriptSerializer();
var dict = oSerializer.Deserialize<Dictionary<string,object>>(json);
var innerDict = dict["Skill"] as Dictionary<string, object>;
if (innerDict != null)
{
foreach (var kvp in innerDict)
{
Console.WriteLine ("{0} = {1}", kvp.Key, kvp.Value);
}
}
Or, the alternative would be to map your object into a proper class and deserialize to it instead of a generic Dictionary<string, object>.
Suppose you have following class
public class Data
{
public string Method { get; set; }
public Skills Skill { get; set; }
// If you don't want to use Skills class then you can use this
//public Dictionary<int, string> Skills { get; set; }
}
public class Skills
{
public int Id { get; set; }
public string Skill { get; set; }
}
So you can Deserialize json into Data Object like this
Data deserializedData = JsonConvert.DeserializeObject<Data>(json);
You should declare your own class:
public class YourClassName
{
public string Method { get; set; }
public Dictionary<int, string> Skill { get; set; }
}
and deserialize the Json string like this:
var obj = oSerializer.Deserialize<YourClassName>(json);

Read a list of dynamic objects into CSV

I'm attempting to read a big list of data into a flat CSV. One field of each row is XML data - with the XML dictating additional Properties in each row. Therefore each row could have slightly different Properties.
I've got my list in an initial structured class:
private class Response {
public Response() {
Values = new Dictionary<string, string>();
}
public string Owner { get; set; }
public string Author { get; set; }
public string Email { get; set; }
public string Data { get; set; } // XML data in here
public Dictionary<string, string> Values { get; set; }
public DateTime Created { get; set; }
}
I then thought to make my list dynamic to handle the varied Properties:
var responses = new List<dynamic>();
foreach (var response in query) {
if (!string.IsNullOrEmpty(response.Data))
{
var doc = new XmlDocument();
doc.LoadXml(response.Data);
foreach (XmlNode node in doc.GetElementsByTagName("field")) {
try
{
response.Values.Add(node.FirstChild.InnerText, node.LastChild.InnerText);
}
catch (Exception ex) {
// log
}
}
}
dynamic fullResponse = new ExpandoObject();
fullResponse.Owner = response.Owner;
fullResponse.Author = response.Author;
fullResponse.Email = response.Email;
fullResponse.Created = response.Created;
IDictionary<string, object> map = fullResponse;
foreach (var value in response.Values) {
if (map.ContainsKey(value.Key)) {
map[value.Key] = value.Value;
}
else {
map.Add(value.Key, value.Value);
}
}
responses.Add(fullResponse);
}
... which also works fine. But now I want to basically flatten this list and export it as a CSV, knowing that each row of my dynamic list might have slightly different properties.
Grabbing the PropertyInfo, a dynamic type, obviously comes back with nothing. Am I just going to have to loop through my list to extract the unique properties manually into something like a DataTable? Or are there some calls I can make with Reflection to get this done more efficiently?
I ended up using a plain old DataTable to get it sorted:
using (var dt = new DataTable())
{
var keys = responses.SelectMany(x => ((IDictionary<string, object>)x).Keys).Distinct();
var columns = keys.Select(x => new DataColumn(x)).ToArray();
dt.Columns.AddRange(columns);
foreach(IDictionary<string, object> response in responses)
{
var row = dt.NewRow();
foreach (var kvp in response)
{
row[kvp.Key] = kvp.Value;
}
dt.Rows.Add(row);
}
// write to CSV
}
Though I feel like I could've done something a lot cooler with Reflection to achieve the same result.

Categories

Resources