I have 2 csv files in Azure Blob storage, I am using C# to parse these files
The first csv file is a small file that contains a mapping from the data in the 2nd csv file to an API The records look like the below
csvField1, apiField1.subfield1
csvField2, apiField2
csvField3, apiField5
csvField6, apiField1.subfield2
the second csv file is big so I will use stream to read it and the file has a header with the following column names
csvField1, csfField2, csvField4, csfField5, csvField6, csfField7
I want the output to be a JSON like the below
{
apiField1:{
subfield1: value(csvField1)
subfield2: value(csvField6)
},
apiField2:value(csvField2),
apiField5: value(csvField3)
}
The workable solution with Newtonsoft.Json library:
A) Create data class for apiField1
class ApiField1
{
public ApiField1(string s1, string s2)
{
subfield1 = s1;
subfield2 = s2;
}
public string subfield1 { get;}
public string subfield2 { get;}
}
B) Create data class for API record
class ApiRecord
{
public ApiRecord(string[] s)
{
apiField1 = new ApiField1(s[0], s[5]);
apiField2 = s[1];
apiField5 = s[2];
}
public ApiField1 apiField1 { get; }
public string apiField2 { get; }
public string apiField5 { get; }
}
C) Test
class Program
{
static void Main(string[] args)
{
ApiRecord a = new ApiRecord("0,1,2,3,4,5".Split(','));
Console.WriteLine(JsonConvert.SerializeObject(a));
Console.ReadLine();
}
}
Result:
{"apiField1":{"subfield1":"0","subfield2":"5"},"apiField2":"1","apiField5":"2"}
I just test with a simple string "0,1,2,3,4,5". In your case, you can read each line from the stream of the CSV file.
Or, you can use a dictionary:
Dictionary<string, String> apidield1 = new Dictionary<string, string>();
apidield1.Add("subfield1", "value(csvField1)");
apidield1.Add("subfield2", "value(csvField6)");
Dictionary<string, Object> apiRecord = new Dictionary<string, object>();
apiRecord.Add("apiField2", "value(csvField2)");
apiRecord.Add("apiField5", "value(csvField3)");
apiRecord.Add("apiField1", apidield1);
Console.WriteLine(JsonConvert.SerializeObject(apiRecord));
Output:
{"apiField2":"value(csvField2)","apiField5":"value(csvField3)","apiField1":{"subfield1":"value(csvField1)","subfield2":"value(csvField6)"}}
Related
I am trying to get the object value but I don't know how to do it. I'm new to C# and its giving me syntax error. I want to print it separately via the method "PrintSample" How can I just concatenate or append the whatData variable . Thank you.
PrintSample(getData, "name");
PrintSample(getData, "phone");
PrintSample(getData, "address");
//Reading the CSV file and put it in the object
string[] lines = File.ReadAllLines("sampleData.csv");
var list = new List<Sample>();
foreach (var line in lines)
{
var values = line.Split(',');
var sampleData = new Sample()
{
name = values[0],
phone = values[1],
address = values[2]
};
list.Add(sampleData);
}
public class Sample
{
public string name { get; set; }
public string phone { get; set; }
public string adress { get; set; }
}
//Method to call to print the Data
private static void PrintSample(Sample getData, string whatData)
{
//THis is where I'm having error, how can I just append the whatData to the x.?
Console.WriteLine( $"{getData. + whatData}");
}
In C# it's not possible to dynamically evaluate expression like
$"{getData. + whatData}"
As opposed to languages like JavaScript.
I'd suggest to use rather switch expression or Dictionary<string, string>
public void PrintData(Sample sample, string whatData)
{
var data = whatData switch
{
"name" => sample.name,
"phone" => sample.phone,
"address" => sample.address
_ => throw new ArgumentOutOfRangeException(nameof(whatData)),
};
Console.WriteLine(data);
}
I'm not sure what you are trying to achieve. Perhaps this will help you:
private static void PrintSample(Sample getData, string whatData)
{
var property = getData.GetType().GetProperty(whatData);
string value = (string)property?.GetValue(getData) ?? "";
Console.WriteLine($"{value}");
}
What PO really needs is
private static void PrintSamples(List<Sample> samples)
{
foreach (var sample in samples)
Console.WriteLine($"name : {sample.name} phone: {sample.phone} address: {sample.address} ");
}
and code
var list = new List<Sample>();
foreach (var line in lines)
{
......
}
PrintSamples(list);
it is radicolous to use
PrintSample(getData, "name");
instead of just
PrintSample(getData.name)
You can do this using reflection. However, it's known to be relatively slow.
public static void PrintSample(object getData, string whatData)
{
Console.WriteLine( $"{getData.GetType().GetProperty(whatData).GetValue(getData, null)}");
}
I've written a DLL that parses XML and returns Dictionary with tag name and its value. I'm using it in other program called ZennoPoster Project Maker. Here's the code:
XMLWork.XMLWorker worker = new XMLWork.XMLWorker(); // My parse class
string path = #"Z:\New\test.xml";
Dictionary<string, string> data = worker.GetData(path); // GetData - method, that returns
// data from XML
project.Variables["second_name"].Value = data["second_name"];
This block of code I must remake into XMLWorker class method and return a project type and in ZennoPoster I have to with 1 line of code return data. How can I do it?
Assuming that you have the following simplified types:
namespace Objects
{
public class Project
{
public Dictionary<string, Variable> Variables { get; set; }
}
public class Variable
{
public object Value { get; set; }
}
}
You could structure your XMLWorker class like this:
using Objects;
public class XMLWorker
{
public Project Project { get; private set; }
public XMLWorker(string path)
{
Project = new Project();
Dictionary<string, string> data = GetData(path);
Project.Variables["second_name"].Value = data["second_name"];
}
internal Dictionary<string, string> GetData(string path)
{
// method implementation
}
}
Sample usage:
var project = (new XMLWork.XMLWorker(#"Z:\New\test.xml")).Project;
is it possible to create a List of my own class from a CSV file?
the file e.g. looks like:
ID;NAME
1;Foo
2;Bar
then I have a class like:
class MyClass
{
public int id { get; set; }
public string name { get; set; }
}
is it possible to generate a list of this class out of the cvs file? maybe with some library
You could use a CSV parser such as FileHelpers or FastCSV. If you don't want to use third party libraries you may take a look at the built-in TextFieldParser class which could be used like that:
public IEnumerable<MyClass> Parse(string path)
{
using (TextFieldParser parser = new TextFieldParser(path))
{
parser.CommentTokens = new string[] { "#" };
parser.SetDelimiters(new string[] { ";" });
parser.HasFieldsEnclosedInQuotes = true;
// Skip over header line.
parser.ReadLine();
while (!parser.EndOfData)
{
string[] fields = parser.ReadFields();
yield return new MyClass()
{
id = fields[0],
name = fields[1]
};
}
}
}
and then:
List<MyClass> list = Parse("data.csv").ToList();
But never, please never roll your own CSV parser as other people suggested you here as answers to your question.
I managed to write to and read a specific parameter from a .ini file.
I was wondering if there was a way to load the entire content of the .ini file and store it in a special class. That way, I only have to load the .ini file once. This way it should reduce the amount of loading that the game will do.
I know that in small games, it propably doesn't matter, but I would still appreciate it if someone could point me in the right direction.
I believe that the creators of C# tend to push people in the direction of XML based config files rather then INI files - so there isn't anything built in. I found this article on CodeProject that wraps things in a nice class. Will this be of any help?
http://www.codeproject.com/Articles/1966/An-INI-file-handling-class-using-C
I didn't write it - and am not taking credit for it, but it may be what you are looking for :)
Assuming the INI is a simple key / value pair split with new line could you use something like this to provide the entire INI file as either a dictionary or a strongly typed object.
the method allows you to load an ini file into an object like this.
class IniStructure
{
public short Field1;
public int Property1 { get; set; }
public string Property2 { get; set; }
}
IniStructure ini = IniLoader.Load<IniStructure>(<fileName>);
or simply in to a dictionary with the non T method.
public static class IniLoader
{
public static T Load<T>(string fileName)
{
T results = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] tProperties = typeof(T).GetProperties();
FieldInfo[] tFields = typeof(T).GetFields();
var iniFile = Load(fileName);
foreach (var property in tProperties)
if (iniFile.ContainsKey(property.Name))
{
object s = System.Convert.ChangeType(iniFile[property.Name].ToString(), property.PropertyType);
property.SetValue(results, s, null);
}
foreach (var field in tFields)
if (iniFile.ContainsKey(field.Name))
{
object s = System.Convert.ChangeType(iniFile[field.Name].ToString(), field.FieldType);
field.SetValue(results, s);
}
return results;
}
public static Dictionary<string, object> Load(string fileName)
{
Dictionary<string, object> results = new Dictionary<string, object>();
string fileText = File.ReadAllText(fileName);
string[] fileLines = fileText.Split('\r');
if (fileLines.Length > 0)
for (int i = 0; i < fileLines.Length; i++)
{
string line = fileLines[i].Trim();
if (!string.IsNullOrEmpty(line))
{
int equalsLocation = line.IndexOf('=');
if (equalsLocation > 0)
{
string key = line.Substring(0, equalsLocation).Trim();
string value = line.Substring(equalsLocation + 1, line.Length - equalsLocation - 1);
results.Add(key, value);
}
}
}
return results;
}
}
I am fairly new to arrays in C# and am used to storing a mass of data in a string and in INI files and then breaking it down into basic arrays using delimiters...so yeh, my knowledge is almost none existent.
My main form class begin this definition:
public CAirportData[] _AirportData; //size not known
This is the method I am using to create the array:
...string[] airports = possibleAirports.Split(','); //size is known
foreach (string airport in airports)
{
string[] rwys = inif.Read(airport, "rwys").Split(':'); //size is known (2)
_AirportData = new CAirportData[] { new CAirportData() { icao=airport, depRwy=rwys[0], arrRwy=rwys[1] } };
}
I know this just boils down to my limited knowledge of objects and arrays. But I can't seem to find anything on the internet that uses this sort of thing. I have tried to combine other peoples code with little success.
I need the _AirportData array to be available outside of the form hence public and declared outside of any methods. I supose the main problem is that I am overwriting array and foreach airport I am creating a new array hence loosing the previous. I had tried moving the ..= new CAirportData[] to all sorts of places but Visual Studio doesn't like it.
Below is the class definition for CAirportData:
public class CAirportData
{
public string icao { get; set; }
public string depRwy { get; set; }
public string arrRwy { get; set; }
public override string ToString()
{
string result = string.Format("ICAO: {0}, Dep: {1}, Arr: {2}", this.icao, this.depRwy, this.arrRwy);
return result;
}
}
public class CMRunways
{
public string icao { get; set; }
public string depRwy { get; set; }
public string arrRwy { get; set; }
}
Many thanks in advance for any help!
What you're looking for is generic List. Change the definition to:
public List<CAirportData> _AirportData = new List<CAirportData>();
Then the code in the loop to:
_AirportData.Add(new CAirportData { icao=airport, depRwy=rwys[0], arrRwy=rwys[1] });
This is what I would do...Create a static class, with a static property (airports) and add a static constructor to load the airports from file at the begining.
public static class Session
{
public static CAirportData[] _AirportData;
static Session()
{
string airports = possibleAirports.Split(",");
foreach (string airport in airports)
{
string[] rwys = inif.Read(airport, "rwys").Split(':'); //size is known (2)
_AirportData = new CAirportData[] { new CAirportData() { icao=airport, depRwy=rwys[0], arrRwy=rwys[1] } };
}
}
}
Now you can access the array anywhere in the project like
MessageBox.Show(Session.CAirportData[0].depRwy);