Store each parsed value of JSON into an array - c#

I'm working on the Array in C#, as following code below, the uricontent is a List in which each string contains one JSON value, I could parse the content, however, I want to have one other array or List to store each parsed value, in the example below, rooms variable can store each time one JSON parsed value, now I wish to store those parsed values in one array.
int i = 0;
while (uricontent.Count != 0)
{
var rooms = JObject.Parse(uricontent[i].ToString())
["rooms"]
.Select(x => new
{
roomID = (string)x["room_name"],
Name = WebUtility.HtmlDecode((string)x["room_name"]),
Price = PriceHelper.Convert((string)x["discountedTotal"]),
Currency = (string)x["currency"],
Occupan = (int)x["adult"]
}).ToArray();
i++;
}
rooms {<>f_AnonymousType11[1]<>f_AnonymousType11[]
[0] { roomID = "Superior 1st floor", Name = "Superior 1st floor", Price = 207.4, Currency = "EUR", Occupan = 2 }
As indicating above, the rooms overwrite the data in each iteration, how can I store those values in one other array like
[1].....
[2].....
....
Thanks

I think what you need is the SelectMany method. SelectMany concatenates all of the IEnumerables generated by the inner Select statements, and returns them as a single IEnumerable, which can then be converted into an array:
var rooms = uricontent
.SelectMany(
uriContentElementJson =>
{
JObject uriContentElement = JObject.Parse(uriContentElementJson);
return uriContentElement["rooms"].Select(
room => new
{
RoomID = (string)room["room_name"],
Name = WebUtility.HtmlDecode((string)room["room_name"]),
Price = PriceHelper.Convert((string)room["discountedTotal"]),
Currency = (string)room["currency"],
Occupant = (int)room["adult"]
});
})
.ToArray();

Related

Merge 2 Object Array Data Series That Share the Same [0] Index

So let's say that you have 2 series of data. (Both object arrays, in your choice of a serialized JSON string, or the actual objects).
For Instance:
string str1 = #"{""datapoints"":[[""02/28/2019"",146800.0],[""02/27/2019"",147700.0],[""02/26/2019"",153900.0]]}";
Then, you have a second series that is very similar...
string str2 = #"{""datapoints"":[[""02/28/2019"",145600.0],[""02/27/2019"",143600.0],[""02/26/2019"",152200.0]]}";
Note: the object arrays inside are both a length of "2", and both contain the same "date" as the [0] index.
How does one merge the 2 object arrays into 1, to yield the following output...
string str3 = #"{""datapoints"":[[""02/28/2019"",145600.0,145600.0],[""02/27/2019"",143600.0,143600.0],[""02/26/2019"",152200.0,152200.0]]}";
For clarity, I'm interested in using the [0] index once, and merging the [1] indexes together. (the number values)
Extra credit if this can be a loop, or can be done with any number of series.
Using json.net, you can deserialize each JSON sample to an object that contains a datapoints property that is an enumerable of object arrays, then merge them using the LINQ methods GroupBy() and Aggregate().
Say the JSON samples to be merged are in a string [][] jsonSeriesList like so:
string str1 = #"{""datapoints"":[[""02/28/2019"",146800.0],[""02/27/2019"",147700.0],[""02/26/2019"",153900.0]]}";
string str2 = #"{""datapoints"":[[""02/28/2019"",145600.0],[""02/27/2019"",143600.0],[""02/26/2019"",152200.0]]}";
var jsonSeriesList = new[] { str1, str2 }; // Add others as required
Then you can create a combined series as follows:
var merged = jsonSeriesList.Aggregate(
new { datapoints = Enumerable.Empty<object[]>() },
(m, j) => new
{
datapoints = m.datapoints.Concat(JsonConvert.DeserializeAnonymousType(j, m).datapoints)
// Group them by the first array item.
// This will throw an exception if any of the arrays are empty.
.GroupBy(i => i[0])
// And create a combined array consisting of the key (the first item from all the grouped arrays)
// concatenated with all subsequent items in the grouped arrays.
.Select(g => new[] { g.Key }.Concat(g.SelectMany(i => i.Skip(1))).ToArray())
});
var mergedJson = JsonConvert.SerializeObject(merged);
Notes:
I am deserializing to an anonymous type for brevity. You could create an explicit data model if you prefer.
I am assuming the individual datapoint arrays all have at least one item.
There is no attempt to sort the resulting merged JSON by series date. You could do that if necessary.
The solution assumes that you will never have multiple component arrays in the same series with the same first item, e.g. "02/28/2019" repeated twice. If so, they will get merged also.
Sample .Net fiddle here.
Here is a simplified example (simplified as validations might be required, but hope it given you a place to start):
Convert it into dot net object
Then go through each date point - for each date point go through all the series, adding the values.
//container object for the json series
public class Container
{
public List<List<object>> datapoints;
}
//Input series in JSON
string[] inputSeries = new string[]
{
"{\"datapoints\": [[\"02/28/2019\", 146800.0],[\"02/27/2019\", 147700.0],[\"02/26/2019\", 153900.0]]}",
"{\"datapoints\": [[\"02/28/2019\", 145600.0],[\"02/27/2019\", 143600.0],[\"02/26/2019\", 152200.0]]}"
};
//Container for input series in dot net object
List<Container> con = new List<Container>();
foreach (var series in inputSeries)
{
con.Add(JsonConvert.DeserializeObject<Container>(series));
}
// output container
Container output = new Container();
output.datapoints = new List<List<object>>();
// assuming all series have equal number of data points.....might not be so
for (int i = 0; i < con[0].datapoints.Count; i++)
{
output.datapoints.Add(new List<object>());
// inner loop is to go across series for the same datapoint....
for (int j = 0; j < con.Count; j++)
{
// add the date if this is the first series....after that only add the values
// right now the assumption is that the dates are in order and match....validation logic might be required
if (j == 0)
{
output.datapoints[i].Add(con[j].datapoints[i][0]);
output.datapoints[i].Add(con[j].datapoints[i][1]);
}
else
{
output.datapoints[i].Add(con[j].datapoints[i][1]);
}
}
}

Finding comma separated String values in a List<int>

I have a comma separated string variable and i need to check its values exists in a given List
string freeServices = "1,7,13,21";
List<int> selectedServices = booking.SelectedServices.Select(x => x.ServiceID).ToList();
i have tried something like this
if (selectedServices.Contains(Convert.Int32(freeServices.Split(','))
{
}
can i do this? or is there any other easy way to find whether the free service ids in selected id list?
To check, all values are contained in SelectedServices:
string freeServices = "1,7,13,21";
var values = freeServices.Split(',').Select(o=>Convert.ToInt32(o)).ToList();
List<int> selectedServices = booking.SelectedServices.Select(x => x.ServiceID).ToList();
if (selectedServices.All(o=>values.Contains(o))
{
}
Try below query, you willget contains records
var containsValues = booking.SelectedServices.where(e=> freeServices.Split(',').Contains(e.ServiceID));
You could use All and int.Parse;
string freeServices = "1,7,13,21";
List<int> selectedServices = booking.SelectedServices.Select(x => x.ServiceID).ToList();
var splittedFreeServices = freeServices.Split(',').Select(k => int.Parse(k));
var result = selectedServices.All(x => splittedFreeServices.Contains(x));
if (result) //booking.SelectedServices contains all elements of freeServices as integer
{
}

Search a Json object array- List vs Dictionary

I deserialized a JsonResponse using the below code.
var data = (JObject)JsonConvert.DeserializeObject(jsonResponse);
I got the response string which looks something like this
{
"results":[
{
"url":"tickets/2063.json",
"id":20794,
"subject":"Device not working",
"created_date": "2018-01-10T13:03:23Z",
"custom-fields":[
{
"id":25181002,
"value":34534
},
{
"id":2518164,
"value":252344
}
]
}
]
}
My objective is to read certain fields in this array of json objects and insert into a database. The fields i require are id, subject, created_date, member_id.
The member id is part of the custom fields. member_id is the value where id=2518164. I've used List to store this, can you let me know if List or Dictionary is better for this case. How to implement a dictionary
var data = (JObject)JsonConvert.DeserializeObject(jsonResponse);
var tickets = data["results"].ToList();
foreach (var ticketItem in tickets){
Int64? ticketFormId = ticketItem["id"].Value<Int64>();
string subject = ticketItem["subject"].Value<string>();
DateTime createdDate = ticketItem["created_date"].Value<DateTime>();
//Do you think for the next step a dictionary is better or a List is better, since I want to search for a particular id=2518164
var fieldsList = ticketItem["fields"].ToList();
foreach(var fieldItem in fieldList){
Int64? fieldId = fieldItem["id"].Value<Int64>();
if(fieldId!=null && fieldId == 2518164){
memberId = fieldItem["value"].Value<string>();
}
}
}
If you're next step to insert them all into the database, just store them into a list. A dictionary is only useful to search the item by a key.
You can also use linq to process the json in a simpler way:
var tickets = JObject.Parse(jsonResponse)["results"]
.Select(ticket => new
{
Id = (long)ticket["id"],
Subject = (string)ticket["subject"],
CreatedDate = (DateTime)ticket["created_date"],
MemberId = (long)ticket["custom-fields"]
.FirstOrDefault(cf => (int)cf["id"] == 2518164)
?["value"],
})
.ToList();

Sort Multi Dimensional/Jagged Array from Api

I need a little help beyond what I have found on stack so far.
I have an array that looks like this (First is this Multi Dimensional or Jagged?)
Second I would like to Sort this by the Start Date which is [X][4]
I have tried several searches and saw the below which I tired
//string[][] SenorityList = SalesEmployees.OrderBy(inner => inner[0][4]).ToArray();
But I dont really understand how it works so cant make it work...
I also saw http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=151 which looks like it may work by using a class but again not understanding it so not sure how to deploy it for my needs.
Below I have added the export I am using that builds the array so you can see the variable names etc.
#region GrabSalesEmployees
DateTime Now = DateTime.Now;
EP203000Content EP203000 = context.EP203000GetSchema();
context.EP203000Clear();
string[][] SalesEmployees;
SalesEmployees = context.EP203000Export(
new Command[] {
EP203000.EmployeeInfo.ServiceCommands.EveryEmployeeID,
EP203000.GeneralInfoEmployeeSettings.EmployeeClass,
EP203000.EmployeeInfo.Status,
EP203000.EmployeeInfo.EmployeeID,
EP203000.EmploymentHistory.Position,
EP203000.EmploymentHistory.StartDate,
EP203000.EmploymentHistory.EndDate
},
new Filter[] {
new Filter { Field = new Field { FieldName = EP203000.GeneralInfoEmployeeSettings.EmployeeClass.FieldName }, Condition = FilterCondition.Equals, Value = "SALES", Operator = FilterOperator.And },
new Filter { Field = new Field { FieldName = EP203000.EmployeeInfo.Status.FieldName }, Condition = FilterCondition.Equals, Value = "Active", Operator = FilterOperator.And },
new Filter { Field = new Field { FieldName = EP203000.EmployeeInfo.EmployeeID.FieldName }, Condition = FilterCondition.NotEqual, Value = "BA00000450", Operator = FilterOperator.And },
},
0, false, false
);
Jagged array is an array of arrays. If you are sure that every inner array contains date in the 4th element you can use next code:
// for each element of external array (1st dimension) order by 4th element of jagged (2nd dimension) by ascending
string[][] SenorityList = SalesEmployees.OrderBy(innerArray => innerArray[4]).ToArray();
Of course the better way is to check elements and cast them to DateTime:
string[][] SenorityList = SalesEmployees.OrderBy(innerArray =>
{
if (innerArray.Length >= 5)
{
DateTime startDate;
if (DateTime.TryParse(innerArray[4], out startDate))
return startDate;
}
// if you want that unpasrsed dates will be on the end of the list use DateTime.MaxValue
return DateTime.MaxValue;
}).ToArray();

Querying a list of strings with a query string?

I have a dictionary:
<string,List<string>>
The key is the product code say "product1" then the list is a list of properties:
"Brand","10.40","64","red","S"
Then I 'can' have a list of rules/filters e.g.
var tmpFilter = new customfilters();
tmpFilter.Field = "2";
tmpFilter.Expression = ">";
tmpFilter.Filter = "10";
So for the above example this would pass because at index 2 (tmpFilter.Field) it is more than 10; then I have another object which defines which fields within the list I want to write to file. For that dictionary item I just want to write the product brand and price where the filters match.
At the moment without the filter I have:
var tmp = new custom();
tmp.Columns = "0,1";
tmp.Delimiter = ",";
tmp.Extention = ".csv";
tmp.CustomFilters = new List<customfilters>() {new customfilters(){ Field = "2", Expression = ">", Filter = "10"} };
public static void Custom(custom custom)
{
foreach (var x in Settings.Prods)
{
//Get Current Product Code
var curprod = Settings.ProductInformation[x];// the dictionary value
foreach (var column in custom.Columns)
{
var curVal = curprod[Convert.ToInt32(column)];
tsw.Write(curVal + custom.Delimiter);
}
Settings.Lines++;
tsw.WriteLine();
}
tsw.Close();
}
I only want to write the curprod if all the filters pass for that list of strings.
How I can do this?
There's a really nice Nuget package based on an example published by Microsoft, that they have decided to make really hard to find for some reason, that allows dynamic linq queries:
https://www.nuget.org/packages/System.Linq.Dynamic/1.0.2
Source:
https://github.com/kahanu/System.Linq.Dynamic
Using that you can do stuff like this very easily (note: I used strings here because the OP states they have a List<string>):
List<string> stuff = new List<string> { "10.40", "64", "5", "56", "99", "2" };
var selected = stuff.Select(s => new { d = double.Parse(s) }).Where("d > 10");
Console.WriteLine(string.Join(", ", selected.Select(s => s.d.ToString()).ToArray()));
Outputs:
10.4, 64, 56, 99
That may give you a place to start. One thing you are going to have to tackle is identifying which of your fields are numeric and should be converted to a numeric type before trying to apply your filter. Otherwise you are going to comparing as strings.

Categories