How to parse this JSON string into 2 List<String> - c#

I have some problem to understand how you parse this JSON string.
As seen we have 2 lists in the JSON string. "bids" and "asks"
For bids for example we have:
0.035314,25.986
0.035313,6.947
etc
The goals is to create 2 lists, bids and asks where each element in the list contains the above. For example each index contains this information then: "0.035314,25.986" etc.
How will one approach this string when doing this?
Expected output should be as an understanding like below:
List<String> bidsLIST = new List<String>();
List<String> asksLIST = new List<String>();
bidsLIST.Add("0.035314,25.986");
bidsLIST.Add("0.035313,6.947");
asksLIST .Add("0.035319,1.139");
asksLIST .Add("0.03532,28.381");
JSON is located here:
https://pastebin.com/j6Xckh49
{"bids":[[0.035314,25.986],[0.035313,6.947],[0.035312,17.441],[0.035308,4],[0.0353,6.188]],"asks":[[0.035319,1.139],[0.03532,28.381],[0.035324,6.7],[0.035329,2.307],[0.03533,6.868]],"nonce":451939443}
This code is not entirely correct:
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
void testparseJSON()
{
String responseBody = "{" +
'"' + "bids" + '"' + ":[[0.035314,25.986],[0.035313,6.947],[0.035312,17.441],[0.035308,4],[0.0353,6.188]]," +
'"' + "asks" + '"' + ":[[0.035319,1.139],[0.03532,28.381],[0.035324,6.7],[0.035329,2.307],[0.03533,6.868]]," +
'"' + "nonce" + '"' + ":451939443}";
var deserializedTickers = JsonConvert.DeserializeObject<Dictionary<List<String>, bidsasks>>(responseBody);
foreach (var bidsasks in deserializedTickers)
{
var Bids = bidsasks.Value.bids;
var Asks = bidsasks.Value.asks;
if (Bids != null && Asks != null)
{
//How to get the 2 lists here?
}
}
}
public class bidsasks
{
public List<String> bids { get; set; }
public List<String> asks { get; set; }
}

You need an intermediate class to reflect the JSON structure:
public class JsonBidsAsks {
public List<List<string>> bids { get; set; }
public List<List<string>> asks { get; set; }
}
Then you can parse the JSON and convert to the desired structure:
var deserializedTicker = JsonConvert.DeserializeObject<JsonBidsAsks>(responseBody);
var ans = new bidsasks {
bids = deserializedTicker.bids.Select(ba => ba.Join(",")).ToList(),
asks = deserializedTicker.asks.Select(aa => aa.Join(",")).ToList(),
};

void testparseJSON(){
String responseBody = "{" +
'"' + "bids" + '"' + ":[[0.035314,25.986],[0.035313,6.947],[0.035312,17.441],[0.035308,4],[0.0353,6.188]]," +
'"' + "asks" + '"' + ":[[0.035319,1.139],[0.03532,28.381],[0.035324,6.7],[0.035329,2.307],[0.03533,6.868]]," +
'"' + "nonce" + '"' + ":451939443}";
var jsnAsObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Rootobject>(responseBody);
var bids = jsnAsObj.bids;
var asks = jsnAsObj.asks;
}
and put at another class (recommended at a new *.cs file) your DM.
this is just a suggestion and not a must, the code can work as an inner class inside of your current one, but it's not recommended.
public class Rootobject
{
public float[][] bids { get; set; }
public float[][] asks { get; set; }
public int nonce { get; set; }
}

You can deserialize your json to anonymous type:
var template = new
{
bids = new[]
{
new[] {1.0, 1.0}
},
asks = new[]
{
new[] {1.0, 1.0}
},
};
var parsedJson = JsonConvert.DeserializeAnonymousType(responseBody, template);
Now just join bids and asks in two lists:
var bidsLIST = parsedJson.bids.Select(b => string.Join(",", b)).ToList();
var asksLIST = parsedJson.asks.Select(a => string.Join(",", a)).ToList();

After checking the #NetMage answer, I manipulated a little that code and Works without problems.
public class bidsasks
{
public List<List<string>> bids { get; set; }
public List<List<string>> asks { get; set; }
public int nonce { get; set; }
}
public static void testparseJSON()
{
String responseBody = "{" +
'"' + "bids" + '"' + ":[[0.035314,25.986],[0.035313,6.947],[0.035312,17.441],[0.035308,4],[0.0353,6.188]]," +
'"' + "asks" + '"' + ":[[0.035319,1.139],[0.03532,28.381],[0.035324,6.7],[0.035329,2.307],[0.03533,6.868]]," +
'"' + "nonce" + '"' + ":451939443}";
var deserializedTicker = JsonConvert.DeserializeObject<bidsasks>(responseBody);
var ans = new bidsasks
{
bids = deserializedTicker.bids,
asks = deserializedTicker.asks
};
for (int i = 0; i < ans.bids.Count; i++)
{
Console.WriteLine(String.Format("PRICE", ans.bids[i][0]));
Console.WriteLine(String.Format("QTY", ans.bids[i][1]));
}
for (int i = 0; i < ans.asks.Count; i++)
{
Console.WriteLine(String.Format("PRICE", ans.asks[i][0]));
Console.WriteLine(String.Format("QTY", ans.asks[i][1]));
}
}
}

Related

C# Iterate through nested properties using IEnumerator

I have seen examples (and official ones) for IEnumerator on lists and arrays or dicts, but I have a different problem. I have classes with properties, how may I implement the IEnumerable and IEnumerator in that case?
My properties classes are:
public class standardMessage
{
public messageProperties message { get; set; }
public messageFlag flag { get; set; }
}
public class messageProperties
{
public string messageSubject { get; set; }
public string messageBody { get; set; }
}
public class messageFlag
{
public Boolean flagImportant { get; set; }
public Boolean flagPersonal { get; set; }
}
And this is the Program:
public class Program
{
static void Main(string[] args)
{
standardMessage myMessage = new standardMessage();
myMessage.message = new messageProperties
{
messageSubject = "Greetings",
messageBody = "Happy Weekend"
};
myMessage.flag = new messageFlag
{
flagImportant = false,
flagPersonal = true
};
//how do I iterate through all properties, without knowing how many are there, instead of writing this worm line of code?
Console.WriteLine(myMessage.message.messageSubject.ToString() + "\r\n" + myMessage.message.messageBody.ToString() + "\r\n" + myMessage.flag.flagImportant.ToString() + "\r\n" + myMessage.flag.flagPersonal.ToString());
Console.ReadLine();
}
}
If you want a production-grade way of printing your objects as a formatted string, you need to go and override ToString in all your classes to return whatever format you want.
However, if you just want to print the things on screen for debugging or logging purposes, why not JSON?
public static string ToJson(object #object) =>
System.Text.Json.JsonSerializer.Serialize(#object, new JsonSerializerOptions{WriteIndented = true});
Console.WriteLine(ToJson(myMessage));
Prints
{
"message": {
"messageSubject": "Greetings",
"messageBody": "Happy Weekend"
},
"flag": {
"flagImportant": false,
"flagPersonal": true
}
}
Quick and dirty, but quick and working.
I made a very primitive object to json converter. I wouldn't use this in production and it's about 30% slower than Newtonsoft but it get's the job done.
private static string PrintObject(object obj, int depth = 1)
{
var type = obj.GetType();
if (type.IsPrimitive || type == typeof(Decimal) || type == typeof(String))
return "\"" + obj.ToString() + "\"";
var props = type.GetProperties();
string ret = "";
for (var i = 0; i < props.Length; i++)
{
var val = props[i].GetValue(obj);
ret += new string('\t', depth) + "\"" + props[i].Name + "\":" + PrintObject(val, depth + 1);
if (i != props.Length - 1)
ret += "," + Environment.NewLine;
}
return ("{" + Environment.NewLine + ret + Environment.NewLine + new string('\t', depth - 1) + "}").Replace("\t", " ");
}
Gives the result
{
"message":{
"messageSubject":"Greetings",
"messageBody":"Happy Weekend"
},
"flag":{
"flagImportant":"False",
"flagPersonal":"True"
}
}

How to create "public string array" from parameter as array?

I have this code:
public static void SendDataToES(String startTimestamp, String startDate, String bid_x, String ask_x)
{
var tem_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
bid = bid_x,
ask = ask_x
};
}
class Pre_Market
{
public string x_ric { get; set; }
public string ask { get; set; }
public string bid { get; set; }
public string date { get; set; }
public string timestamp { get; set; }
}
.
But in the future, it will have parameters as Array.
public static void SendDataToES(String startTimestamp, String startDate, String bid_x, String ask_x, IList nameABC, String[] getABCs)
which nameABC[] has value A,B,C and getABC[] has value 1,2,3 so I would like to create in class Pre_Market as Array
public string[] A { get; set;}
public string[] B { get; set;}
public string[] C { get; set;}
Not sure below is working fine ?
for ( int i = 0 ; i < nameABC.Count(); i++ )
{
public string[] nameABC[i] { get; set; }
}
so that the below is available ?
var tem_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
bid = bid_x,
ask = ask_x,
A = getABC[0],
B = getABC[1],
C = getABC[2]
};
Updated ! Below is working fine on my side.
var temp_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
fids = new Dictionary<string, string>(),
};
for (int i = 0; i < nameFIDs.Count() - 1; i++)
{
temp_ehm.fids.Add(nameFIDs[i], get_FIDs[i]);
}
"fids in temp_ehm can be added" that’s news to me!
If you are ok with using an anonymous class instead of Pre_Market, then You can build up your object structure in JSON ( building a string is easy ), and then use a JSON deserializer (install NewtonSoft.JSON via NuGet) to convert it to an object
Here how you may want to generate your JSON string
string jsonStr = "{ timestamp = \"" + startTimestamp + "\"," +
"date = \"" + startDate + "\"," +
"bid = \"" + bid_x + "\"," +
"ask = \"" + ask_x + "\"";
for ( int i = 0 ; i < nameABC.Count(); i++ )
{
jsonStr += "," + nameABC[i] + " = \"" + getABCs[i] + "\""
}
jsonStr += "}";
A simple solution would be to use a dictionary.
public static void SendDataToES(String startTimestamp, String startDate, String bid_x, String ask_x, IList<string> nameABC, string[] getABCs)
{
var tem_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
bid = bid_x,
ask = ask_x,
ABCs = new Dictionary<string, string>()
};
int i = 0;
foreach (string name in nameABCs)
tem_ehm.Add(name, getABCs[i++];
// access the ABCs like so:
string A = tem_ehm.ABCs["A"];
string B = tem_ehm.ABCs["B"];
string C = tem_ehm.ABCs["C"];
}
class Pre_Market
{
public string x_ric { get; set; }
public string ask { get; set; }
public string bid { get; set; }
public string date { get; set; }
public string timestamp { get; set; }
public Dictionary<string, string> ABCs { get; set; }
}

C# parse textual file in a specific format

I have never done something like this so I'm really curious on how this can be performed. I imagine it can be either done via regex or in c# somehow...
I have a textual file with data in following format:
12.23.45.56:8080:username:password
12.23.45.56:8080:username:password
12.23.45.56:8080:username:password
12.23.45.56:8080:username:password
I have prepared a class which looks like following:
public class ParsedData
(
public string IP { get; set; }
public string Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
)
The desired output how I would like it to be is that I can parse each line individually and 1 line should have the data stored in a parsed object (list of ParsedData);
How could do this, and to parse the each line of data individually ?
Can someone help me out ?
var completedList = text.Split(':').Select(pr => new ParsedData
{
IP = pr.ElementAt(0).ToString() // this should be the IP But I'm getting the
// Index was outside the bounds of the array. exception in this part
/*My elements here*/
}).ToList();
It looks like at least one row doesn't have any data in it, maybe there is an empty row in the input data?
Try printing out each row of data before selecting the first element of the array - then you can see which input is causing the exception.
You may use Regex (.+?):(.+?):(.+?):(.+), here example:
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace Main {
public struct ParsedData {
public string IP { get; set; }
public string Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
class Prog {
static List<ParsedData> pdl = new List<ParsedData>();
static string file = #"12.23.425.56:90:kukur:psiar%4
151.23.255.52:3131:Zandga:Ikurit
52.23.45.56:5125:Ningame:Mirsga!#
112.223.45.56:4000:Bisgo:One0ne";
static void Main() {
var re = new Regex(#"(.+?):(.+?):(.+?):(.+)");
foreach (Match m in re.Matches(file)) {
pdl.Add(new ParsedData() { IP = m.Groups[1].Value, Port = m.Groups[2].Value, Username = m.Groups[3].Value, Password = m.Groups[4].Value });
Console.WriteLine("IP: " + m.Groups[1] + " PORT: " + m.Groups[2] + " USR_NM: " + m.Groups[3] + " PASS: " + m.Groups[4]);
}
}
}
}
Also I added an List which contains the data.
class Program
{
static void Main(string[] args)
{
//I think you know how to read the file so:
string text =
#"12.23.45.56:8080:username:password
12.23.45.56:8080:username:password
12.23.45.56:8080:username:password
12.23.45.56:8080:username:password";
List<ParsedData> ps = new List<ParsedData>();
text.Split(new char[] { '\r','\n' }, StringSplitOptions.RemoveEmptyEntries).ToList().ForEach(c =>
{
var cols = c.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).ToList();
//you can check too if cols have content here
ps.Add(new ParsedData()
{
IP = cols[0]!=null?cols[0]:"", //and check if inside it's content..
Port = cols[1],
Username = cols[2],
Password = cols[3]
});
});
foreach(ParsedData p in ps)
{
Console.WriteLine(p.IP + "\t" + p.Port + "\t" + p.Username + "\t" + p.Password);
}
}
}
public class ParsedData
{
public string IP { get; set; }
public string Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
I think you make misunderstood about the pr, it not array now, it the element in the array.
var text = "12.23.45.56:8080:username:password";
var array = text.Split(':');
var data = new ParsedData()
{
IP = array[0],
Port = array[1],
Username = array[2],
Password = array[3]
};

linq query to parse given complex xml

I have a xml like below with root as rail
<rail>
<timetable>
<trainParts>
<trainPart id="tp_1" name="1" timetablePeriodRef="ttp_2012_13" categoryRef="cat_Commuter" processStatus="planned" trainNumber="1">
<operatingPeriodRef ref="Daily" />
<ocpsTT>
<ocpTT ocpType="begin" ocpRef="ocp_SWH">
<sectionTT trackInfo="SWH-DM" />
</ocpTT>
<ocpTT ocpType="stop" ocpRef="ocp_SE">
<times arrival="16:16:00" departure="16:18:00" scope="scheduled" />
<sectionTT trackInfo="SE-DM" />
</ocpTT>
.
.
.
so on
</ocpsTT>
</trainPart>
</trainParts>
</timetable>
</rail>
Now like this there are many train numbers whose details I have to parse in one go.
I can parse one child and its attributes at a time using linq but i want to parse all the childs and its elements.
Say for trainNumer="1" i need to get
categoryRef
processStatus
operatingPeriodRef
ocpType
ocpRef
trackInfo
arrival
departure
NOTE: In some cases times tag containing departure arrival is not there
I did try to write the code as below:
public void trainDetails(string trainNumber)
{
var xdoc = XDocument.Load("Rail.xml");
XNamespace ad = "http://www.rail.org/schemas/2009";
var train = (from t in xdoc.Root.Elements(ad + "timetable")
let d = t.Element(ad + "trainParts").Element("trainPart")
where (string)t.Attribute("number") == trainNumber
select new
{
operatingPeriod=(from s1 in d.Elements(ad+"operatingPeriodRef")
operatingref=(string)s1.Attribute("ref")
}).ToList()
}
select new
{
trainOcpsTT= (from s2 in d.Elements(ad + "ocpsTT").Elements(ad+"ocpTT")
select new
{
ocpType=(string)s2.Attribute("ocpType"),
ocpRef=(string)s2.Attribute("ocpRef")
}).ToList()
}).FirstOrDefault();
}
}
I am unable to frame the query properly..
Is it Possible to get all these in one xml linq query itself?How?
If not then which is the proper approach in this case..
Here is my proposal:
public class TrainInfo
{
public string categoryRef { get; set; }
public int trainNumber { get; set; }
public string processStatus { get; set; }
public string operatingPeriodRef { get; set; }
public List<ocpsTTs> ocpsTT { get; set; }
}
public struct ocpsTTs
{
public string ocpType;
public string ocpRef;
public string arrival;
public string departure;
public string scope;
public string trackInfo;
}
class Program
{
static void Main(string[] args)
{
TrainInfo ti = ProcessXml(#"XMLFile1.xml", 1);
}
static TrainInfo ProcessXml(string xmlfile, int trainnumber)
{
TrainInfo retVal;
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlfile);
XNamespace xns = "http://www.rail.org/schemas/2009";
XDocument xdoc = System.Xml.Linq.XDocument.Parse(xmlDoc.InnerXml);
retVal =
(from c
in xdoc.Root.Elements(xns + "timetable").Elements(xns + "trainParts").Elements(xns + "trainPart")
where c.Attribute("trainNumber").Value.Equals(trainnumber.ToString())
select new TrainInfo
{
categoryRef = c.Attribute("categoryRef").Value,
trainNumber = Int32.Parse(c.Attribute("trainNumber").Value),
processStatus = c.Attribute("processStatus").Value,
operatingPeriodRef = c.Element(xns + "operatingPeriodRef").Attribute("ref").Value,
ocpsTT = (from tt in c.Elements(xns + "ocpsTT").Descendants(xns + "ocpTT")
let timeinfo = tt.Elements(xns + "times").Any()
select new ocpsTTs
{
ocpType = tt.Attribute("ocpType").Value,
ocpRef = tt.Attribute("ocpRef").Value,
arrival = timeinfo ? tt.Element(xns + "times").Attribute("arrival").Value : string.Empty,
departure = timeinfo ? tt.Element(xns + "times").Attribute("departure").Value : string.Empty,
scope = timeinfo ? tt.Element(xns + "times").Attribute("scope").Value : string.Empty,
trackInfo = tt.Element(xns + "sectionTT").Attribute("trackInfo").Value,
}).ToList()
}).FirstOrDefault();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
retVal = null;
}
return retVal;
}
}

concating string with comma to join a long string

I am getting a List of below class.
public class SmsResponse
{
public string AliasName { get; set; }
public string CellPhoneNumber { get; set; }
public int Response { get; set; }
}
I am passing this list to a function to check if the response field has response other than 0 , if it have than it is a error for which i have to prepare a status string by this method PrepareStatusString();.
bool isSuccess = EvaluateSmsResponse(responseList); //list of smsresponse class
private bool EvaluateSmsResponse(List<SmsResponse> smsResponseList)
{
bool isSent = smsResponseList.Exists(response => response.Response != 0);
if (!isSent)
PrepareStatusString(smsResponseList);
return isSent;
}
private void PrepareStatusString(List<SmsResponse> responseList)
{
bool isfirst = true;
foreach (var item in responseList)
{
if (item.Response != 0)
{
if(isfirst)
StatusDescription += item.AliasName + "|" + item.CellPhoneNumber + "|" + item.Response.ToString();
else
StatusDescription += "," + item.AliasName + "|" + item.CellPhoneNumber + "|" + item.Response.ToString();
isfirst = false;
}
}
}
The code is working as desired, but can it be optimized/improved in any way. I am feeling there is a scope improvement but not able to figure out ??
If you're using .NET 4 or newer, you can override SmsResponse.ToString() and then use String.Join<T>(String, IEnumerable<T>) to concatenate the responses.
So your SmsResponse class may look something like this:
public class SmsResponse
{
public string AliasName { get; set; }
public string CellPhoneNumber { get; set; }
public int Response { get; set; }
public override string ToString()
{
return AliasName + "|" + CellPhoneNumber + "|" +
Response.ToString();
}
}
And PrepareStatusString would be:
private void PrepareStatusString(List<SmsResponse> responseList)
{
StatusDescription = string.Join(",", responseList.Where(i => i.Response != 0));
}
StringBuilder will be more efficient at appending strings within the foreach loop (depending on num of iterations)
private void PrepareStatusString(List<SmsResponse> responseList)
{
bool isfirst = true;
StringBulder sb = new StringBuilder();
foreach (var item in responseList)
{
if (item.Response != 0)
{
if(isfirst)
sb.AppendFormat("{0}|{1}|{2}", item.AliasName, item.CellPhoneNumber,item.Response.ToString());
else
sb.AppendFormat(",{0}|{1}|{2}", item.AliasName, item.CellPhoneNumber, item.Response.ToString());
isfirst = false;
}
}
StatusDescription = sb.ToString();
}
I don't know about optimization, but it could be rewritten more expressively as follows:
private void PrepareStatusString(List<SmsResponse> responseList)
{
StatusDescription = responseList
.Where(x => x.Response != 0)
.Select(x => x.AliasName
+ "|" + x.CellPhoneNumber
+ "|" + x.Response.ToString())
.Aggregate((x, y) => x + "," + y);
}
Note that StringBuilder will only offer a noticeable performance benefit if you expect more than a couple hundred objects there.
Use string.Join like so
List<string> elements = new List<string>();
foreach (var item in responseList)
{
if (item.Response != 0)
{
elements.add(item.AliasName + "|" + item.CellPhoneNumber + "|" + item.Response.ToString());
}
}
string result = string.Join(",", elements.ToArray());

Categories