Deserialize a JSON with nested arrays to generate a string from values - c#

In my application I have a List<Users>
[{
"Id": "1",
"Name": "last, first",
"Skills": [{"SN":"20","SL":"12"},{"SN":"197","SL":"09"}]
},
{
"Id": "2",
"Name": "Black, Jack",
"Skills": [{"SN":"40","SL":"07"},{"SN":"199","SL":"05"}]
},
{
"Id": "3",
"Name": "Rooney, Wayne",
"Skills": [{"SN":"40","SL":"11"},{"SN":"201","SL":"07"}]
}]
I need to convert this data into one string in a format like this:
"1/last, first/20-12,197-09;2/Black, Jack/40-07,199-05;3/Rooney,
Wayne/40-11,201-07"
I tried to serialize this object to get a JSON string:
public IHttpActionResult ImportUsers([FromBody]IEnumerable<Users> newUsers)
{
string agents = JsonConvert.SerializeObject(newUsers);
return Ok(agents);
}
and get a result:
"[{\"Id\":\"1\",\"Name\":\"last,
first\",\"Skills\":[{\"SN\":\"20\",\"SL\":\"12\"},{\"SN\":\"197\",\"SL\":\"09\"}]},{\"Id\":\"2\",\"Name\":\"Black,
Jack\",\"Skills\":[{\"SN\":\"40\",\"SL\":\"07\"},{\"SN\":\"199\",\"SL\":\"05\"}]},{\"Id\":\"3\",\"Name\":\"Rooney,
Wayne\",\"Skills\":[{\"SN\":\"40\",\"SL\":\"11\"},{\"SN\":\"201\",\"SL\":\"07\"}]}]"
Than I tried to deserialize this string to get values for each variables
var dict = JsonConvert.DeserializeObject<dynamic>(agents);
List<string> results = new List<string>();
foreach (var d in dict)
{
var skills = d["Skills"];
string skill = string.Join(",", skills);
string list = d["Id"] + "/" + d["Name"] + "/" + skill;
results.Add(list);
}
string result = string.Join(";", results);
and get this string:
"1/last, first/{\r\n \"SN\": \"20\",\r\n \"SL\": \"12\"\r\n},{\r\n
\"SN\": \"197\",\r\n \"SL\": \"09\"\r\n};2/Black, Jack/{\r\n \"SN\":
\"40\",\r\n \"SL\": \"07\"\r\n},{\r\n \"SN\": \"199\",\r\n \"SL\":
\"05\"\r\n};3/Rooney, Wayne/{\r\n \"SN\": \"40\",\r\n \"SL\":
\"11\"\r\n},{\r\n \"SN\": \"201\",\r\n \"SL\": \"07\"\r\n}"
So it's more like what I need, but I still have a problem with values in Skills list. How can I get values from it like it was with Id and Name columns? Maybe I need to deserialize this part one more time or use some regular expressions to achieve the string that I need?

Your expected result is not a valid json. Then the better way is to format result string via c# without 3rd party libraries.
Laconic way is to use string functiions:
public IHttpActionResult ImportUsers([FromBody] IEnumerable<User> newUsers)
{
var agents = string.Join(";", newUsers.Select(GetFormattedUserString));
return Ok(agents);
}
private string GetFormattedUserString(User user)
{
return string.Concat(user.Id, "/", user.Name, "/", string.Join(",", user.Skills.Select(skill => string.Concat(skill.SN, "-", skill.SL))));
}
Efficient and less understandable (for my opinion) way is to use StringBuilder:
public IHttpActionResult ImportUsers([FromBody] IEnumerable<User> newUsers)
{
var sb = new StringBuilder();
foreach (var user in newUsers)
{
sb.Append(user.Id);
sb.Append("/");
sb.Append(user.Name);
sb.Append("/");
for (int i = 0; i < user.Skills.Length; i++)
{
sb.Append(user.Skills[i].SN);
sb.Append("-");
sb.Append(user.Skills[i].SL);
if (i != user.Skills.Length)
sb.Append(",");
}
sb.Append(";");
}
var result = sb.ToString();
return Ok(result);
}

You can slightly modify your code to make it work. In order to get the skills in the way you want, you can nest another foreach loop that will create a list of skills in the requested format:
var dict = JsonConvert.DeserializeObject<dynamic>(agents);
List<string> results = new List<string>();
foreach (var d in dict)
{
List<string> skills = new List<string>();
foreach (var s in d["Skills"])
{
skills.Add(s["SN"].ToString() + "-" + s["SL"].ToString());
}
string skill = string.Join(",", skills);
string list = d["Id"] + "/" + d["Name"] + "/" + skill;
results.Add(list);
}
string result = string.Join(";", results);

Related

C# Deserialize string of multiple arrays with json-string in it explicit to List<string>

i have a json-string, or bit more something like a "string of arrays":
"[
{
"type":"radio-group",
"label":"Radio-Button-Gruppe",
"name":"radio-group-1556028993486",
"className":"iCheck",
"values":[
{
"label":"aaaaaaa",
"value":"aaaaaaa"
},
{
"label":"bbbbbbbbb",
"value":"bbbbbbbbb"
},
{
"label":"cccccccccccc",
"value":"cccccccccccc"
}
]
}
],
[
...
],
[
{
"type":"header",
"label":"Überschrift"
}
]"
Now I want to have a List<string> of each array in this string. Something like:
List<string> x[0] = "{
"type":"radio-group",
"label":"Radio-Button-Gruppe",
"name":"radio-group-1556028993486",
"className":"iCheck",
"values":[
{
"label":"aaaaaaa",
"value":"aaaaaaa"
},
{
"label":"bbbbbbbbb",
"value":"bbbbbbbbb"
},
{
"label":"cccccccccccc",
"value":"cccccccccccc"
}
]
}"
What's the best way to do that?
I already tried out JsonConvert.DeserializeObject<IEnumerable<string>>() but my problem is that he wants to deserialize my jsons to an object. But I want to keep them as a string und put them to my list.
Why I need a list of string for each array?
Because I use the json-strings inside the arrays to render a form. each array show you a page of the form, and the json is the data for rendering this form.
to render this form i have to go through a loop through all of this arrays and render the json in it for every page.
You can use JsonConvert.DeserializeObject<IEnumerable<JToken>>(json) where json is each of your top level arrays. Then you can iterate through the results and use .ToString() on each JToken object.
As others have pointed out, you don't have valid JSON, so I didn't try to give a solution to parse out the top level arrays.
var json = #"[
{
""type"":""radio-group"",
""label"":""Radio-Button-Gruppe"",
""name"":""radio-group-1556028993486"",
""className"":""iCheck"",
""values"":[
{
""label"":""aaaaaaa"",
""value"":""aaaaaaa""
},
{
""label"":""bbbbbbbbb"",
""value"":""bbbbbbbbb""
},
{
""label"":""cccccccccccc"",
""value"":""cccccccccccc""
}
]
}
]";
var arrays = new[] { json };
var objectsAsStrings = new List<string>();
foreach (var array in arrays)
{
var tokens = JsonConvert.DeserializeObject<IEnumerable<JToken>>(array);
foreach (var token in tokens)
{
objectsAsStrings.Add(token.ToString());
}
}
var json = "yourjson";
var jsonnew = "[" + json+ "]";
var list = JsonConvert.DeserializeObject<dynamic>(jsonnew);
var result = new List<string>();
foreach (var item in list)
{
var str = JsonConvert.SerializeObject(item);
result.Add(str);
}
You can use this , too.

how do I extract a specific substring from a string in c# using a loop?

I am trying to extract just the route number from a response I get from a web server. The response looks like this;
[{"Description":"METRO Blue Line","ProviderID":"8","Route":"901"},{"Description":"METRO Green Line","ProviderID":"8","Route":"902"},
All I need is to get the route numbers so I can populate a combobox with them. I am trying to use a loop as there are quite a few. My current solution gets the first route number, but then for some reason I only get the provider number after that.This is what I have so far.
//get bus routes and popluate the busRoutecmb
restClient.endPoint = routeUrl + formatLine;
string response = restClient.request();
//show me what was returned for debug puposes
System.Diagnostics.Debug.Write(response);
//sort through data and put relevent item in a list
List<string> responseItems = new List<string>();
//splitting into routes
string[] splitByRoute = response.Split('}');
//extracting route number from elements in splitByRoute
List<string> extractedRouteNums = new List<string>();
foreach (string thing in splitByRoute)
{
//splitting each bus route up by piece of information
string[] splitByWord = thing.Split(',');
//getting rid of everything but the route number
int length = splitByWord.Length;
int count = 2;
while (count <= length)
{
string[] word = splitByWord[count].Split(':');
string routeNum = word[1].Trim('"');
count += 3;
extractedRouteNums.Add(routeNum);
System.Diagnostics.Debug.WriteLine(count);
System.Diagnostics.Debug.WriteLine(routeNum);
}
}
//add repsonse to busRoutecmb
busRoutecmb.DataSource = extractedRouteNums;
}
Gratzy is right about this being JSON, but I would propose you use JSON.NET to deserialize it.
var items = JsonConvert.DeserializeObject<JArray>(response);
var routeNumbers = items.Select(i => i.Value<string>("Route")).ToList();
You could also use http://json2csharp.com/ to produce a strongly-typed model, and deserialize to that model type if you prefer.
public class RootObject
{
public string Description { get; set; }
public string ProviderID { get; set; }
public string Route { get; set; }
}
var items = JsonConvert.DeserializeObject<RootObject[]>(response);
var routeNumbers = items.Select(i => i.Route).ToList();
What your getting back is basically a JSON string which is just an array of name value pairs or a Dictionary List.
[{
"Description": "METRO Blue Line",
"ProviderID": "8",
"Route": "901"
},
{
"Description": "METRO Green Line",
"ProviderID": "8",
"Route": "902"
}]
You can deserialize that string into a List in several ways one is to use System.Web.Script.Serialization.JavaScriptSerializer or JSON.NET. Once in a List you can query that list and return just the route key,Value pair.
var data = "[{ Description:\"METROBlueLine\",ProviderID:\"8\",Route:\"901\"},{Description:\"METRO Green Line\",ProviderID:\"8\",Route:\"902\"}]";
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
var mylist = ser.Deserialize<List<Dictionary<string,string>>>(data);
//or JSON.net
var mylist = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
var routes = mylist.SelectMany(a => a).Where(c => c.Key == "Route").ToList();
foreach (var route in routes)
Console.Write(route);
output
[Route, 901][Route, 902]
If you really only want the values then
var routesonly = routes.Select(r => r.Value).ToList();

how to make a case insensitive dictionary for var input - C#

var fruitDictionary = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) { { "Apple" , "Fruit" }, { "Orange", "Fruit" }, { "Spinach", "Greens" } };
TextRange textRange = new TextRange(richTextBox1.Document.ContentStart, richTextBox1.Document.ContentEnd);
string data = textRange.Text;
var output = new StringBuilder(data);
foreach (var kvp in fruitDictionary)
output.Replace(kvp.Key, kvp.Value);
var result = output.ToString();
richTextBox2.AppendText(result);
It works normally but if the input isnt in format it wont work. For example on Apple the output is Fruit but on apple it still says apple
By setting the dictionary's comparer to StringComparer.InvariantCultureIgnoreCase, key lookup became culture and case invariant -- i.e. var a = fruitDictionary["apple"]; and var b = fruitDictionary["ApPlE"] will yield the same results. That said, you perform your replace operation on an instance of StringBuilder which is not related to that. Both StringBuilder.Replace and String.Replace don't have overloads that let you configure string comparison options, so you would have to make an extension method.
public static string Replace(this string str, string oldValue, string newValue,
StringComparison comparison = StringComparison.Ordinal)
{
var index = str.IndexOf(oldValue, comparison);
while (index >= 0)
{
str = str.Remove(index, oldValue.Length);
str = str.Insert(index, newValue);
index = str.IndexOf(oldValue, comparison);
}
return str;
}
var fruitDictionary = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) { { "Apple" , "Fruit" }, { "Orange", "Fruit" }, { "Spinach", "Greens" } };
TextRange textRange = new TextRange(richTextBox1.Document.ContentStart, richTextBox1.Document.ContentEnd);
string data = textRange.Text;
foreach (var kvp in fruitDictionary)
data = data.Replace(kvp.Key, kvp.Value, StringComparison.InvariantCultureIgnoreCase)
richTextBox2.AppendText(data);

MongoDB aggregation Shell script to MongoC# Driver

How can I convert this Mongo Shell script to MongoDB C# Driver?
var myItems = []
var myCursor = db.Tickets.aggregate(
[
{ $match : { TicketProjectID : 49 } },
{ $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } }
// I will have a list of fields that I need to concatenate at run time. So C# query should support concatenation for "N" number of fields at run-time.
//{ $group: { _id: null, count: { $sum: 1 } } }
],
{ allowDiskUse: true }
)
//This seems like a ugly performance approach when we are working against 100k results with above match
while (myCursor.hasNext()) {
var item = myCursor.next();
if(item.concatValue.search(/mysearchkey/i) > -1)
{
myItems.push(item.TicketID)
}
}
myItems
or is there a better way to do the string search in concatenated projection instead of foreach in cursor, as some quires might get 50k records.
This is what I have tried so far, (Not using Aggregation)
Note: Trimmed this code to suite for public Q&A sites. So please consider this as Pseudo-code
var tickets = ticketsCollection.FindSync(filter).ToList();
string concatinatedValue = string.Empty;
foreach (var ticket in tickets)
{
foreach (var field in customFieldsForThisProject)
concatinatedValue += ticket[field.Replace(" ", "_")];
if(concatinatedValue.StripHtml().contains("MysearchWord"))
{
TikectIdList.Add(ticket["TicketID"])
}
}
Thanks to #Nikola.Lukovic, working on his pseudo-code, I came up with this working solution.
Approach one: fully using C# Driver
var ticketsCollection = _mongoConnect.Database.GetCollection<BsonDocument>("Tickets");
var dbResult = from ticket in ticketsCollection.AsQueryable()
select new
{
TicketProjectID = ticket["TicketProjectID"],
TicketID = ticket["TicketID"],
ConcatValue = ticket["Status"] + (string) ticket["Name"]
};
var matches = from dbr in dbResult
where dbr.ConcatValue.Contains(searchKey)
where dbr.ConcatValue.StartsWith(searchKey)
select dbr;
This will not work for my scenario as fields I am trying to
concatenate are if type string, but $add will only work with
numeric and date types.
Approach two: using RunCommand and passing straight Shell command. This will work for all datatypes. And works for my need as well.
var projectCommand =
BsonDocument.Parse(
"{ $project: { _id: -1, TicketProjectID:1, TicketID:1, concatValue: { $concat: [ \"$Status\", \" - \", \"$Name\" ] } } }");
var matchCommand =
BsonDocument.Parse("{ $match: {concatValue: { $regex: '" + searchKey + "', $options: 'i'} } }");
var pipeline = new[] {projectCommand, matchCommand};
var result = ticketsCollection.Aggregate<BsonDocument>(pipeline).ToList();
if (result.Count > 0)
return result.Select(x => (int)x["TicketID"]).ToList();
return null;
Edited according to the given comment
If you can use AsQueryable() you can get the values like this:
var dbResult = from ticket in ticketsCollection.AsQueryable()
where ticket.TicketProjectID == 49
select new
{
TicketProjectID = ticket.TicketProjectID,
TicketID = ticket.TicketID,
ConcatValue = ticket.Status + " - " + ticket.Name
};
and than later you can do something like this:
var result = from dbr in dbResult
where dbr.ConcatValue.Contains("something") //or
where dbr.ConcatValue.StartsWith("something")//or you can use regex
select dbr;
Note: For some reason both Status and Name properties from type Ticket need to be of a type String for concatenation to work since mongo driver won't recognize the call to ToString() from some other type.
If you want to concatenate properties from some other types you could get them separately from the db and than concat them locally.
note, i'm not that good with mongo shell i could mess something up but you can see in which way you could go
Alternatively you could write your shell command like this and put it in a string:
var command = #"db.Tickets.aggregate(
[
{ $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } },
{ $match : { TicketProjectId : 49, concatValue : { $regex : /mysearchkey/i } } }
],
{ allowDiskUse : true }
);";
then execute it in c# with RunCommandAsync method from MongoDatabase.
var result = await mongoDatabase.RunCommandAsync<BsonDocument>(BsonDocument.Parse(command));

Create comma separated string from portion of strings in C# List

I have a C# List that I want to create a comma separate string. I've found other answers on SO that deal with this, but my particular case I want to only use a portion of the values in the List to create the string.
If my List contained these values:
"Foo"
"Bar"
"Car"
and I wanted to create a string
Foo, Bar and Car.
I could use this code:
string.Format("{0} and {1}.",
string.Join(", ", myList.Take(myList.Count - 1)),
myList.Last());
However, my list is actual formed of jSON values like so
{ Name = "Foo" }
{ Name = "Bar" }
{ Name = "Car" }
So the above code results in:
{ Name = "Foo" }, { Name = "Bar" } and { Name = "Car" }.
How would I construct the string such that I only use the Foo, Bar and Car values in the list?
Update
Thanks to #StevePy, this is what I ended up with:
string.Format("{0} and {1}.",
string.Join(", ", myList.Select(x => x.Name).ToList().Take(myList.Count - 1)),
myList.Select(x => x.Name).ToList().Last());
If you need to operate with strings, just grab the necessary part of each string with, for example, String.IndexOf and String.LastIndexOf methods:
List<string> myList = new List<string> {
"{ Name = \"Foo\" }",
"{ Name = \"Bar\" }",
"{ Name = \"Car\" }"
};
var temp = myList.Select(x =>
{
int index = x.IndexOf("\"") + 1;
return x.Substring(index, x.LastIndexOf("\"") - index);
})
.ToList();
string result = string.Format("{0} and {1}.",
string.Join(", ", temp.Take(myList.Count - 1)),
temp.Last());
Linq should help.
var nameList = myList.Select(x=>x.Name).ToList();
you can use JsonConvert.toString to get the value of your list item, or if you used a json serialization, you could use the JsonConvert.Deserialization
I built a method that will do this for you:
static string ConvertToMyStyle(List<string> input)
{
string result = "";
foreach(string item in input)
{
if(input.IndexOf(item) != input.ToArray().Length-1)
result += item + ", ";
else
result += "and " + item + ".";
}
return result;
}
this handles the single item case
protected string FormatWithOxfordCommas(List<string> reasons)
{
string result = "";
if (reasons.Count == 1)
result += reasons[0];
else
{
foreach (string item in reasons)
{
if (reasons.IndexOf(item) != reasons.Count - 1)
result += item + ", ";
else
result += "and " + item + ".";
}
}
return result;
}

Categories

Resources