Convert delimited string to Expando Object - c#

I lave a dictionary like this -
Dictionary<string, Object> dict = new Dictionary<string, Object>();
dict.Add("event.data", "data");
dict.Add("event.Location", LocObj);
dict.Add("event.Details.Cost", CostObj);
I am trying to merge this with the existing json structure -
{
"event" : {
"name" : "Hello World",
"tags" : [tags]
}
"sponsors" : {
...
}
"OtherObj" : {
...
}
}
I am trying to use ExpandoObject and then inject it into the original json, like this-
foreach(KeyValuePair<string, Object> kvp in dict) {
var newObj= new ExpandoObject() as IDictionary<string, Object>;
newObj.Add(kvp.Key, value);
existingObject.Merge(JObject.FromObject(newObj), new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Union
});
}
Console.WriteLine(JsonConvert.SerializeObject(existingObject));
But when it gets serialized event.Location does not show up inside the existing event tag, instead it adds a new key called event.Location.
{
"event" : {
"name" : "Hello World",
"tags" : [tags]
},
"event.Location" : { ... }, <---------------
"event.data": { ... }, <---------------
"event.Details.Cost" : { ... }<---------------
"sponsors" : {
...
},
"OtherObj" : {
...
}
}
How do I fix the Expando obj creation to fix this?

See the below program. This will show an example of a working merge and breaking merge. The difference is how the object is structured. In one case, there is "Event.Location" which does not work. In the other case, the "Event" object contains a "Location" and it correctly nests in the JObject's merge operation.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Dynamic;
namespace DynamicSerial
{
class Program
{
static void Main(string[] args)
{
var myObject = new Dictionary<string, Object>();
myObject.Add("Id", 1);
myObject.Add("Event", new { Name = "SomeName", Id = 2 });
var mergeObject = new Dictionary<string, Object>();
mergeObject.Add("Event", new { Location = new { Name = "SomeLocation", Id = 3 } }); //WORKS
//mergeObject.Add("Event.Location", new { Name = "SomeLocation", Id = 3 }); //DOES NOT WORK
JObject myDynamicObject = JObject.FromObject(myObject);
foreach (KeyValuePair<string, Object> kvp in mergeObject)
{
var newObj = new ExpandoObject() as IDictionary<string, Object>;
newObj.Add(kvp.Key, kvp.Value);
myDynamicObject.Merge(JObject.FromObject(newObj), new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Merge
});
}
Console.WriteLine(JsonConvert.SerializeObject(myDynamicObject));
}
}
}
The resulting JSON
good:
{"Id":1,"Event":{"Name":"SomeName","Id":2,"Location":{"Name":"SomeLocation","Id":3}}}
bad:
{"Id":1,"Event":{"Name":"SomeName","Id":2},"Event.Location":{"Name":"SomeLocation","Id":3}}
In conclusion, you should change
Dictionary<string, Object> dict = new Dictionary<string, Object>();
dict.Add("event.data", "data");
dict.Add("event.Location", LocObj);
dict.Add("event.Details.Cost", CostObj);
To
Dictionary<string, Object> dict = new Dictionary<string, Object>();
dict.Add("event", new { data="data", Location=LocObj, Details=new { Cost=CostObj } });

Related

The call is ambiguous between IDictionary<string, object> and IDictionary

I am using a Library with a class that have the following constructors:
public JobDataMap(IDictionary<string, object> map);
public JobDataMap(IDictionary map);
I created an instance of JobDataMap:
var jdm = new JobDataMap(new Dictionary<String, Object> {
{ "Manager", myObject }
});
But I am getting the compilation error:
The call is ambiguous between the following methods or properties:
'JobDataMap.JobDataMap(IDictionary<string, object>)' and 'JobDataMap.JobDataMap(IDictionary)'
How to solve this?
You can enforce the type being passed like so:
var jdm = new JobDataMap((IDictionary<string, object>)new Dictionary<String, Object> {
{ "Manager", myObject }
});
Or you could make a factory method and make the non-generic constructor (I'm assuming you use this less) private:
public class JobDataMap
{
public JobDataMap(IDictionary<string, object> map)
{
}
private JobDataMap(IDictionary map)
{
}
public static JobDataMap FromNonGenericMap(IDictionary map)
{
return new JobDataMap(map);
}
}
Usage:
var jdm = JobDataMap.FromNonGenericMap(someNonGenericDictionary);
and then you can use the regular generic one like so:
var jdm = new JobDataMap(new Dictionary<String, Object> {
{ "Manager", myObject }
});
You can cast it to the type for the constructor you want it to use:
var jdm = new JobDataMap((IDictionary<string, object>) new Dictionary<String, Object> {
{ "Manager", new object() }
});
This design does seem a bit dubious, however...

Multi string array to multi dictionary in C#?

I got stuck to change the following array to a dictionary.
public static string[][,] patterns = new string[][,]
{
new string[,] {
{ "1,2,3" },
{ "3,2,5" },
},
new string[,] {
{ "4,4,3" },
{ "7,1,2" },
},
};
This is what I have:
public Dictionary<string, string[]> patterns = new Dictionary<string, string[]>();
I can't fill the array with predefined values.
I want to change to a dictionary, because it has a key.
Can I also change the above array to a key and values format?
I want something like this: { "keyNameExample1", "1,2,3", "4,5,6", "etc"}. I want do something like this: patterns["keyNameExample", 1 (integer array pack)]; or patterns["keyNameExample", 2]; (to get the second arrays)
{ "keyNameExample1", "1,2,3", "4,5,6", "etc"} { "keyNameExample2", "5,7,8", "1,1,1", "etc"} and get it like this: patterns["keyNameExample1", 2]; or patterns["keyNameExample2", 1];
can make it even shorter like:
public static Dictionary<string, string[]> demo = new Dictionary<string, string[]>
{
{ "abc", new[]{"1","2"}},
{ "def", new[]{"3","4"}},
};
and with C# 9 you can even do:
public static Dictionary<string, string[]> demo = new()
{
{ "abc", new[]{"1","2"}},
{ "def", new[]{"3","4"}},
};
You can just make it a dictionary with a list, and I guess that covers your requirements (index access, variable number of integers for the index element). Here is an example (for the value list I am not sure, whether you really want a string or ints, in case just change the type):
// define dictionary
IDictionary<string, IList<int>> dict = new Dictionary<string, IList<int>>();
// assign values
dict["abc"] = new List<int> { 2, 4, 8 };
dict["def"] = new List<int> { 10, 12, 14 };
// get value
int dictDef2 = dict["def"][1];
Finally, I got it.
public static Dictionary<string, string[]> demo = new Dictionary<string, string[]>
{
{ "abc",
new string[]
{
"1",
"2"
}
},
{ "def",
new string[]
{
"3",
"4"
}
},
};
Contains check:
if (demo.ContainsKey("abc"))
{
}
Get the value(s):
demo["abc"][0]
Thanks for any help.
If you want to change existing array, you can try Linq:
using System.Linq;
...
public static string[][,] patterns = new string[][,] {...}
...
public Dictionary<string, string[]> patternsDict = patterns
.Select((value, index) => (
key : $"keyNameExample{index}",
value : value.OfType<string>().ToArray()))
.ToDictionary(pair => pair.key, pair => pair.value);
Note, that we have to convert (flatten) 2d array into ordinal one
If you want just to declare dictionary and fill it:
public Dictionary<string, string[]> patterns = new Dictionary<string, string[]>() {
{"keyExample1", new string[] { "1,2,3", "3,2,5" }},
{"keyExample1", new string[] { "4,4,3", "7,1,2" }},
};
public string[][,] patterns = new string[][,] { new string[,] { { "1,2,3" }, { "3,2,5" } }, new string[,] { { "4,4,3" }, { "7,1,2" } } };
Dictionary<string, string[,]> patternsDictionary = new Dictionary<string, string[,]>();
for (int i = 0; i < patterns.Length; i++)
{
patternsDictionary.Add(i.ToString(), patterns[i]);
}
Console.WriteLine(patternsDictionary["0"][0,1]); // Returns 2 - from { "1,2,3" }

Do I really need to create and return the collection for this method?

I have seen people use yield return, although every time I try and use it in foreach it tells me something along the lines of: The body of CollectDictionary cannot be an iterator block because Dictionary<string, object> is not an interator interface type
I have a lot of methods line the following, is there a way to reduce boilerplate?
public Dictionary<string, object> CollectDictionary()
{
var configLines = File.ReadAllLines(_file).Where(IsValidConfigLine);
var configElements = new Dictionary<string, object>();
foreach (var configElement in configLines)
{
configElements.Add(configElement.Split("=")[0], configElement.Split("=")[1]);
}
return configElements;
}
You can reduce the amount of code by using .ToDictionary().
public Dictionary<string, object> CollectDictionary()
{
string[] configLines = new string[]
{
"foo1=bar1",
"foo2=bar2",
"foo3=bar3",
"foo4=bar4",
};
return configLines.Select(configElement => configElement.Split("="))
.ToDictionary(splt => splt[0], splt => (object)splt[1]);
}
This should return the following Dciotnary
{
{ "foo1", "bar1" },
{ "foo2", "bar2" },
{ "foo3", "bar3" },
{ "foo4", "bar4" }
}

Nested foreach to LINQ in multi-level dictionary

I would like to simplify below nested foreach loops using LINQ but couldn't figure out the way. I guess I can use SelectMany using lambda but not sure. I want to create list of objects of ClassA after this nested iteration. Any help is appreciated:
public List<ClassA> GetLists(Dictionary<string, Dictionary<IEnumerable, Dictionary<string, ClassB>>> groups)
{
var retOutput = new List<ClassA>();
foreach (KeyValuePair<string, Dictionary<IEnumerable, Dictionary<string, ClassB>>> group1 in groups)
{
foreach (KeyValuePair<IEnumerable, Dictionary<string, ClassB>> group2 in group1.Value)
{
foreach (KeyValuePair<string, ClassB> group3 in group2.Value)
{
GetList(retOutput, group1.Key,
group2.Key,
group3);
}
}
}
return retOutput;
}
private static void GetList(List<ClassA> retOutput,
string group1Key,
IEnumerable group2Key,
KeyValuePair<string, ClassB> group3)
{
List<List<string>> itemIdsLists = group3.Value.ItemId.IntoChunks(2000);
foreach (var itemIdList in itemIdsLists)
{
var currentRequest = new ClassA
{
TransactionType = group1Key,
Filters = new Dictionary<string, object>(),
ItemIds = new List<string>(),
PropStreamsDict = new Dictionary<string, Tuple<long, string>>()
};
if (group2Key is Dictionary<string, object>)
{
currentRequest.Filters = (Dictionary<string, object>)group2Key;
}
currentRequest.PropStreamsDict.Add(group3.Key, Tuple.Create(group3.Value.StreamId,
group3.Value.Uom));
currentRequest.ItemIds.AddRange(itemIdList);
retOutput.Add(currentRequest);
}
}
You should use SelectMany to make nested foreach.
Here what I come up with:
public List<ClassA> GetLists(Dictionary<string, Dictionary<IEnumerable, Dictionary<string, ClassB>>> groups)
{
return groups
.SelectMany(grp1 => grp1.Value
.SelectMany(grp2 => grp2.Value
.SelectMany(grp3 => grp3.Value.ItemId
.IntoChunks(2000)
.Select(itemIdList =>
new ClassA
{
TransactionType = grp1.Key,
Filters = grp2.Key is Dictionary<string, object> ?
(Dictionary<string, object>)grp2.Key :
new Dictionary<string, object>(),
ItemIds = new List<string>(itemIdList),
PropStreamsDict = new Dictionary<string, Tuple<long, string>>
{
{ grp3.Key, Tuple.Create(grp3.Value.StreamId, grp3.Value.Uom) }
}
}
)
)
)
)
.ToList();
}
You didn't post your ClassA and ClassB so I had to guess.

convert IDictionary data into JSON string using NewtonJSON

how can I convert IDictionary data into JSON using NewtonJSON. My IDictionary data contains the following data:
type: 19
id : 4433
Now I want to convert it into
{
"type":"19",
"id": "4433"
}
How do I do this?
IDictionary<string, string> messageData = message.Data;
var json = JsonConvert.SerializeObject(messageData, new JsonSerializerSettings()
{
Formatting = Formatting.Indented
});
here is the update please see my screenshots
Json.NET (formely Newtonsoft.Json) already has the built in capability to convert dictionaries into Json objects:
// the dictionary may be anything IDictionary<string, whatever>, Json.NET will convert it anyway
IDictionary<string, string> dict = new Dictionary<string, string>()
{
{ "type", "19" },
{ "id" ,"4433"}
};
var json = JsonConvert.SerializeObject(dict, new JsonSerializerSettings()
{
Formatting = Formatting.Indented
});
Outputs:
{
"type": "19",
"id": "4433"
}
Demo: https://dotnetfiddle.net/a562kK
[Edit]
The type you are trying to serialize is not an IDictionary at all. You should try to convert it to a dictionary first.
Here an example (assuming message.Data implements at least IEnumerable):
var dict = new Dictionary<string, string>();
foreach(var item in message.Data)
{
// get Key and Value from item here
var kvp = item as KeyValuePair<string, string>; // this is just an example, I do not know what type your message.Data is returning
dict.Add(kvp.Key, kvp.Value);
}
// now you may serialize `dict`
var list = d.Select(x => new obj{ type = x.Key, id = x.Value});
var json = JsonConvert.SerializeObject(list);
Class:
public class obj
{
public string type { get; set; }
public string id { get; set;}
}

Categories

Resources