I'm working on a project where I want to build tokens from a JSON Array.
//Data fed to the system
{"Fruits":[{"Number":"111", "Name":"Apple"}, {"Number":"112", "Name":"Orange"},{"Number":"113", "Name":"Peach"}]}
//serializes the http content to a string
string result = Request.Content.ReadAsStringAsync().Result;
//deserializes result
Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(result);
//builds custom tokens
var customTokens = new Dictionary<string, object>();
foreach (var dataField in data)
{
if (dataField.Value is JArray)
{
string nameValue = "";
foreach (JObject content in dataField.Value.Children<JObject>())
{
foreach (JProperty prop in content.Properties())
{
nameValue += prop.Name.ToString() + " : " + prop.Value.ToString();
}
}
customTokens.Add($"{dataField.Key}", nameValue);
}
}
The above code managed to create token $Fruits.
But i also want to achieve token $Number and $Name, where values of each token is from the concatenated values of same key. Example, If I use the "$Number", it will be replaced by 111, 112, 113 and If I use the $Name, it will be replaced by Apple, Orange, Peach.
Also, I'm not using any strongly type models as I don't know what data will be fed to the system.
Any help?
There are a few minor changes to your code to achieve this. First make your dictionary look like this:
var customTokens = new Dictionary<string, List<string>>();
Then, when you loop over all the properties in the array, check if the property has been added, and if not add it.
foreach (JProperty prop in content.Properties())
{
if(customTokens.ContainsKey(prop.Name))
{
customTokens[prop.Name].Add(prop.Value.ToString());
}
else
{
customTokens.Add(prop.Name, new List<string> { prop.Value.ToString() });
}
}
At the end you have a dictionary where the key is the property name and the value is a List<string> - this can be concatenated together:
foreach(var item in customTokens)
{
Console.WriteLine(item.Key + ":" + String.Join(",", item.Value));
}
Or, if you really want it in a dictionary of concatenated strings just do this
var finalResult = customTokens.ToDictionary(k => k.Key, v => String.Format(",",v.Value));
Note you'll need to add using System.Linq to the top of your file to use ToDictionary
Final test code:
var result = "{ \"Fruits\":[{\"Number\":\"111\", \"Name\":\"Apple\"}, {\"Number\":\"112\", \"Name\":\"Orange\"},{\"Number\":\"113\", \"Name\":\"Peach\"}]}";
Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(result);
var customTokens = new Dictionary<string, List<string>>();
foreach (var dataField in data)
{
if (dataField.Value is JArray)
{
foreach (JObject content in dataField.Value.Children<JObject>())
{
foreach (JProperty prop in content.Properties())
{
if(customTokens.ContainsKey(prop.Name))
{
customTokens[prop.Name].Add(prop.Value.ToString());
}
else
{
customTokens.Add(prop.Name, new List<string> { prop.Value.ToString() });
}
}
}
foreach(var item in customTokens)
{
Console.WriteLine(item.Key + ":" + String.Join(",", item.Value));
}
}
}
Related
from an API I get a json like this:
66 results of an player with somewhat 31 attributes containing single values or an array of values.
{"api":
{"results":66,
"players":
[{
"player_id":10,
"player_name":"Gustavo Ferrareis",
... (some 31 stats)
"shots":{
"total":13,
"on":2
},
...
},
"player_id":21,
...
}]
}
And I wanted to know if there's a way to deserialize the collection of players into an Dictionary or better DataTable with all 31 attributes without a custom player class or accessing every attribute individually?
So far I tried accessing the players list by:
var data = JObject.Parse(json);
foreach (var field in data)
{
var data2 = JObject.Parse(field.Value.ToString());
foreach (var field2 in data2)
{
if (field2.Key.ToString() == "players")
{
dynamic array2 = JsonConvert.DeserializeObject(field2.Value.ToString());
foreach (var field3 in array2)
Console.WriteLine("Player_id: " + field3.player_id.ToString() + " - Player_name: " + field3.player_name.ToString());
}
}
}
which returns
Player_id: 10 - Player_name: Gustavo Ferrareis
Player_id: 22 - Player_name: GetĂșlio
Player_id: 22 - Player_name: GetĂșlio
I imagine something like:
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach (var player in array2)
dict.Add(player.Key(), player.Value());
The answer can't be that I have to make an custom player class and then use that?
Open for any advice.
Thank you.
You can use Newtonsoft.Json.Linq and get the required result as shown below:
var jObject = JObject.Parse(jsonFromAPI)["api"];
var formattedPlayers = jObject["Players"].Children()
.Select(p => $"Player_id: {p["player_id"]} - Player_name: {p["player_name"]}");
or if you wanted dictionary, then use below:
var playersDictionary = jObject["Players"].Children().Select(p => new {player_id = p["player_id"], player_name = p["player_name"]}).ToDictionary(x => x.player_id, v => v.player_name);
If you want to display all properties of Players, then you need to run loop something like below:
var allPlayerDetails = new List<Dictionary<string, object>>();
foreach (JObject player in jObject["Players"].Children())
{
var playerDictionary = player.Properties()
.ToDictionary<JProperty, string, object>(property => property.Name, property => property.Value);
allPlayerDetails.Add(playerDictionary);
}
for (var index = 0; index < allPlayerDetails.Count; index++)
{
var playerDictionary = allPlayerDetails[index];
Console.WriteLine(Environment.NewLine);
Console.WriteLine(string.Format("Printing Player# {0}", index));
foreach (var d in playerDictionary)
{
Console.WriteLine(d.Key + " - " + d.Value);
}
}
If you want to convert to DataTable from list of players, then you can do something like below:
DataTable dt = new DataTable();
foreach (var column in allPlayerDetails.SelectMany(p => p.Keys).Select(k => k.Trim()).Distinct())
{
dt.Columns.Add(new DataColumn(column));
}
foreach (var details in allPlayerDetails)
{
var dr = dt.NewRow();
foreach (DataColumn dc in dt.Columns)
{
dr[dc.ColumnName] = details.ContainsKey(dc.ColumnName) ? details[dc.ColumnName] : null;
}
dt.Rows.Add(dr);
}
Fiddler can be found here.
You could parse into IEnumerable<string> like this:
IEnumerable<string> = JObject.Parse(json)["players"]
.Children()
.Select(jo => $"Player_id: {jo["player_id"]} - Player_name: {jo["player_name"]});
A similar approach would work for Dictionary using ToDictionary instead of Select, but it depends on what you consider key and value.
Here is the single line code to get the playerid and playername to List or Dictionary
//To List
var resultToList = JObject.Parse(jsonstring)["api"]["players"]
.Select(p => (p["player_id"].ToString(), p["player_name"].ToString()))
.ToList();
//To Dictionary
var resultToDict = JObject.Parse(jsonstring)["api"]["players"]
.Select(p => (p["player_id"].ToString(), p["player_name"].ToString()))
.ToDictionary(x=>x.Item1, y=>y.Item2);
I have a file consisting of a list of text which looks as follows:
Example csv file
There csv file has consist of 3 columns. The first columns will always be the length of 5. So I want to loop through the file content, store those first 5 letters as Key and remaining column as value. I am removing comma between them and Substringing as follows to store.
static string line;
static Dictionary<string, string> stations = new Dictionary<string, string>();
static void Main(string[] args)
{
// Dictionary<string, List<KeyValuePair<string, string>>> stations = new Dictionary<string, List<KeyValuePair<string, string>>>();
var lines = File.ReadAllLines(".\\ariba_sr_header_2017122816250.csv");
foreach (var l in lines)
{
line = l.Replace(",", "");
stations.Add(line.Substring(14),line.Substring(14, line.Length-14));
}
//read all key and value in file
foreach (KeyValuePair<string, string> item in stations)
{
Console.WriteLine(item.Key);
Console.WriteLine(item.Value);
}
Console.ReadLine();
}
After debug, the output is
Output
My Expected Result is as follow:
Expected Result
I cannot see any KeyValuePair here. You have
00021,00014,Ordered
00021,00026,Ordered
00024,00036,Ordered
...
and you want
00021
00021
00024
000014Ordered
000026Ordered
000036Ordered
...
outcome which seems to be IEnumerable<string>. You can try Linq for this
var result = File
.ReadLines(".\\ariba_sr_header_2017122816250.csv")
.Line(line => line.Split(','))
.SelectMany(items => new string[] {
items[0],
$"0{items[1]}{items[2]}" })
.OrderBy(item => item.Length);
foreach (var item in result)
Console.WriteLine(item);
Here we Split each line like 00021,00014,Ordered into separate items: {00021, 00014, Ordered}anf then combine them back with a help ofSelectMany`. We want
00021 which is items[0]
000014Ordered which is 0 + items[1] + items[2]
Finally we want to have short items first - OrderBy(item => item.Length)
Here you go:
var stations = new Dictionary<string, string>();
var lines = File.ReadAllLines(#"C:\temp\22.txt");
foreach (var l in lines)
{
var lsplit = l.Split(',');
if (lsplit.Length > 1)
{
var newkey = lsplit[0];
var newval = lsplit[1] + lsplit[2];
stations[newkey] = newval;
}
}
//read all key and value in file
foreach (KeyValuePair<string, string> item in stations)
{
Console.WriteLine(item.Key + " = " + item.Value);
}
Console.ReadLine();
Not exactly the output you expected, but hopefully it helps.
I have below json in string as parameter to a WebMethod.
How can I deserialize in such a way that value comes in Key value pair.
Json String Parameter:
["Ref No,0","Date,0","Amt,0","Sender Name,0","Sender Add,0","Beneficiary Name,0","Beneficiary Add,0","Phone,0","Secret Code,0","Secret Ans,0","Preferred Id,0"]
WebMethod:
[System.Web.Services.WebMethod]
public static string SaveMappings(string mappingData)
{
//string str = "{\"Arg1\":\"Arg1Value\",\"Arg2\":\"Arg2Value\"}";
//JavaScriptSerializer serializer = new JavaScriptSerializer();
//object obj;
//var data = serializer.Deserialize(mappingData,);
var data = mappingData.ToArray();
if (data != null)
{
}
var d2 = mappingData.Split(',');
if (d2!=null)
{
}
return mappingData;
}
If you need to work with JSON data then use Newtonsoft.JSON library.
Convert the object to an array of strings and then split every line.
With this approach you can be sure that the given string is actually an JSON array and it is correct.
var str = "[\"Ref No,0\",\"Date,0\",\"Amt,0\",\"Sender Name,0\",\"Sender Add,0\",\"Beneficiary Name,0\",\"Beneficiary Add,0\",\"Phone,0\",\"Secret Code,0\",\"Secret Ans,0\",\"Preferred Id,0\"]";
string[] objs = JsonConvert.DeserializeObject<string[]>(str);
Dictionary<string, string> dic = new Dictionary<string, string>();
foreach (var obj in objs)
{
var keyValue = obj.Split(',');
dic.Add(keyValue[0], keyValue[1]);
}
foreach (var record in dic)
{
Console.WriteLine("{0} => {1}", record.Key, record.Value);
}
Or this one using LINQ. It looks better and it can be written faster. However, it is less optimal (two calls of Split instead of one).
public Dictionary<string, string> FromJsonArray(string jsonArray)
{
return JsonConvert.DeserializeObject<string[]>(jsonArray)
.ToDictionary(obj => obj.Split(',')[0], obj => obj.Split(',')[1]);
}
// ...
var str = "[\"Ref No,0\",\"Date,0\",\"Amt,0\",\"Sender Name,0\",\"Sender Add,0\",\"Beneficiary Name,0\",\"Beneficiary Add,0\",\"Phone,0\",\"Secret Code,0\",\"Secret Ans,0\",\"Preferred Id,0\"]";
foreach (var record in FromJsonArray(str))
{
Console.WriteLine("{0} => {1}", record.Key, record.Value);
}
why don't you just change every ',' in the string array to ':' then pass it to the method, from what you wrote in the question, this should work
I'm actually trying to check if a string is equal to any of the key's in my Dictionary object.
Here is what I have done so far:
using (var oStreamReader = new StreamReader(path))
{
Dictionary<String, String> typeNames = new Dictionary<string, string>();
typeNames.Add("Kind","nvarchar(1000)");
typeNames.Add("Name","nvarchar(1000)");
DataTable oDataTable = new DataTable();
var headLine = oStreamReader.ReadLine().Trim().Replace("\"", "");
var columnNames = headLine.Split(new[] { ';' });
String[] oStreamDataValues;
/*
*create DataTable header with specific datatypes and names
*/
int countCol = 0;
foreach (string readColumn in columnNames)
{
if ((readColumn.ToString().Replace("\"", "").CompareTo(typeNames) == true))
{
// this comparison doesn't work
}
}
}
I am not quite sure what exactly you are trying to achieve. If you have a C# dictonary you can use linq to check for values that match the required value, e.g.
string valueToCompare = "Value to match";
Dictionary<string, string> dict = new Dictionary<string, string>
{
{"Key 1", "A value"},
{"Key 2", "Another value"}
};
bool found= dict.Values
.Any(value
=>
value.Equals(valueToCompare,
StringComparison.CurrentCultureIgnoreCase)
);
Since you want check if exist an entry in your Dictionary that as the same key of one of the values in your columnNames object I suggest you to use ContainsKey method
Dictionary<string, string> d = new Dictionary<string, string>();
string keyvalue;
if (d.ContainsKey("value to find"))
{
if (d.TryGetValue("value to find", out keyvalue))
{
//// here keyvalue variable has the value
}
else
{
///value is null or throws exception
}
}
else
{
////key no exists
}
I have solved this (by inspiration of Paul Houlston and Thomas Lielacher)
string headLine = oStreamReader.ReadLine().Trim().Replace("\"", "");
string columnNames = headLine.Split(new[] { ';' });
foreach (string readColumn in columnNames)
{
if (typeNames.Keys.Contains(readColumn, StringComparer.CurrentCultureIgnoreCase) == true)
{
DataColumn oDataColumn = new DataColumn(readColumn,typeof(System.String));
oDataTable.Columns.Add(oDataColumn);
}
}
I want to get some params from Request
I need from Request.Params all params with text contains "txt" I have more type of text structure:
"ctl00$cphMain$repDelTypes$ctl00$ucDel$txtPhone"
"ctl00$cphMain$repDelTypes$ctl00$ucDel$txtPhone2"
"ctl00$cphMain$repDelTypes$ctl00$ucDel$txtPhone3"
"ctl00$cphMain$repDelTypes$ctl00$ucDel$txtAdr1"
"ctl00$cphMain$repDelTypes$ctl00$ucDel$txtAdr2"
"ctl00$cphMain$repDelTypes$ctl00$ucDel$txtAdr3"
how Get value all text after "txt"
var dictionary = new Dictionary<string, string>();
foreach (var key in Request.Params.AllKeys)
{
if (key.ToString().Contains("txt"))
{
// add to dictionary name and value
// dictionary.Add("name", "val");
}
}
You can do this:
var dictionary = new Dictionary<string, string>();
foreach (var key in Request.Params.AllKeys)
{
if (key.ToString().Contains("txt"))
{
int index = Request.Params[key].LastIndexOf("txt");
Dictionary.Add(key, Request.Params[key].SubString(index));
}
}
Are you asking how to add to the dictionary?
var dictionary = new Dictionary<string, string>();
foreach (var key in Request.Params.AllKeys)
{
if (key.ToString().Contains("txt"))
{
//get the text after "txt"
var index = Request.Params[key].LastIndexOf("txt");
var val = Request.Params[key].SubString(index);
Dictionary.Add(key, val);
}
}
var dictionary = new Dictionary<string, string>();
foreach (var key in Request.Params.AllKeys)
{
if (key.ToString().Contains("txt"))
{
// add to dictionary name and value
dictionary.Add(key.Split(new string[]{"txt"}, StringSplitOptions.None)[1], Request.Params[key]);
}
}