Sorting select with cast - c#

Is it possible to do special formatted order in c#?
I have *.json file with data like
{
"RECORDS": [
{
"ROWW": "279166",
"ALBUMID": "3",
"LINK": "https://...1"
},
{
"ROWW": "279165",
"ALBUMID": "1",
"LINK": "https://...2"
},
{
"ROWW": "279164",
"ALBUMID": "2",
"LINK": "https://...3"
}]
}
... a lot of records. And I need to get DataRows ordered by Roww casted like number.
That's How I trying to do this:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
//...
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public class RECORD_PHOTO
{
public string ROWW { get; set; }
public string ALBUMID { get; set; }
public string LINK { get; set; }
}
public class PhotoObject
{
public List<RECORD_PHOTO> RECORDS { get; set; }
}
public List<string[]> listForJson = new List<string[]>();
public List<String> PHOTO_Rows = new List<String>();
public List<String> PHOTO_AlbumIds = new List<String>();
public List<String> PHOTO_Links = new List<String>();
string JsonFileName = #"C:\temp_work\test.json"
public DataTable dtFromJson;
private void Starting()
{
string jsonn = File.OpenText(JsonFileName).ReadToEnd();
var result = JsonConvert.DeserializeObject<PhotoObject>(JsonFileName);
PHOTO_Rows = result.RECORDS.Select(p => p.ROWW).ToList();
PHOTO_AlbumIds = result.RECORDS.Select(p => p.ALBUMID).ToList();
PHOTO_Links = result.RECORDS.Select(p => p.LINK).ToList();
for (int i = 0; i < PHOTO_Rows.Count; i++)
{
listForJson.Add(new string[] { PHOTO_Rows[i], PHOTO_AlbumIds[i], PHOTO_Links[i]});
}
dtFromJson = ConvertListToDataTable(VKPH);
dtFromJson.Columns[0].ColumnName = "ROWW";
dtFromJson.Columns[1].ColumnName = "ALBUMID";
dtFromJson.Columns[2].ColumnName = "LINK";
//
DataRow[] rows = dtFromJson.Select("", "ROWW ASC");
}
}
}
But Sorting in Select by "ROWW" worked like String so I need to add some cast like:
DataRow[] rows = dtFromJson.Select("", "TO_NUMBER(ROWW) ASC");
But this is wrong

The DataColumn.Expression property can be used to add another column to the table that maintains an int version of your ROWW column:
dtFromJson.Columns.Add("ROWWint", typeof(int)).Expression = "CONVERT([ROWW], 'System.Int32')";
You can then orderby this column in your Select
DataRow[] rows = dtFromJson.Select("", "ROWWint");
See it in action: https://dotnetfiddle.net/Cuh2np
--
You could also query the row collection using LINQ:
dtFromJson = dtFromJson.Cast<DataRow>().OrderBy(x => Convert.ToInt32((string)x["ROWW"])).ToArray();

if you want to sort by ROWW just like number then try below piece of code:
string jsonn = File.OpenText(JsonFileName).ReadToEnd();
//Your code modified. Initially it was reading file name .
//Now reading json string from file.
var result = JsonConvert.DeserializeObject<PhotoObject>(jsonn);
//Sort by ROWW after converting to int.
var sortedByRowwResult = result.RECORDS.OrderBy(x => Convert.ToInt32(x.ROWW)).ToList();
After this you can put into data table. But please check your requirement. Is it really required to put json into datatable?

Related

C# merge 2 almost identical JSON objects

A while ago I made a function that merged JSON together.
I had a table looking like this, which in this example has been made by left joining the table 'friends' on the table 'persons':
Id
Name
FriendName
FriendAge
1
Danny
Jason
19
1
Danny
Cesie
18
2
Jason
Danny
19
And it would result in a json object looking like this:
[
{
"Id": 1,
"Name": "Danny",
"Friends": [
{
"Name": "Jason",
"Age": 19
},
{
"Name": "Cesie",
"Age": 18
}
]
},
{
"Id": 2,
"Name": "Jason",
"Friends": [
{
"Name": "Danny",
"Age": 19
}
]
}
]
I did this by using the following C# code:
using System;
using System.Data;
using Newtonsoft.Json;
namespace JsonTest
{
class Program
{
private class Result
{
public int Id { get; set; }
public string Name { get; set; }
public Friend[] Friends { get; set; }
}
private class Friend
{
public string Name { get; set; }
public int Age { get; set; }
}
static void Main(string[] args)
{
string json = "[{\"Id\":1,\"Name\":\"Danny\",\"FriendName\":\"Jason\",\"FriendAge\":19},{\"Id\":1,\"Name\":\"Danny\",\"FriendName\":\"Cesie\",\"FriendAge\":18},{\"Id\":2,\"Name\":\"Jason\",\"FriendName\":\"Danny\",\"FriendAge\":19}]";
// Original table from example
DataTable dt = JsonConvert.DeserializeObject<DataTable>(json);
// Get distinct values from DataTable
DataView dv = new DataView(dt);
DataTable distinct_values = dv.ToTable(true, "Id");
Result[] result = new Result[distinct_values.Rows.Count];
int i = 0;
foreach (DataRow row in distinct_values.Rows)
{
// Filter the original table on one Id from the distinct values
dv.RowFilter = $"Id = {row["Id"]}";
DataTable temp_dt = dv.ToTable();
Result temp = new Result();
// Copy general data over to the temp
temp.Id = Convert.ToInt32(temp_dt.Rows[0]["Id"].ToString());
temp.Name = temp_dt.Rows[0]["Name"].ToString();
Friend[] rows = new Friend[temp_dt.Rows.Count];
// loop over all the rows and copy the array data over
int j = 0;
foreach (DataRow temprow in temp_dt.Rows)
{
rows[j] = new Friend();
rows[j].Name = temprow["FriendName"].ToString();
rows[j].Age = Convert.ToInt32(temprow["FriendAge"].ToString());
j++;
}
// Assign everything to where it it supposed to be
temp.Friends = rows;
result[i] = temp;
i++;
}
Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
Console.ReadLine();
}
}
}
It works really well. But my question, is there another, cleaner or faster, way to do this entire operation? If so, where can I find this? Thanks in advance.
I would create a model to carry your data easier than using DataTable
public class RequestModel{
public int Id { get; set; }
public string Name { get; set; }
public string FriendName { get; set; }
public int FriendAge { get; set; }
}
Then you can try to use lambda to make it, using GroupBy method get grouping by Id, Name.
string json = "[{\"Id\":1,\"Name\":\"Danny\",\"FriendName\":\"Jason\",\"FriendAge\":19},{\"Id\":1,\"Name\":\"Danny\",\"FriendName\":\"Cesie\",\"FriendAge\":18},{\"Id\":2,\"Name\":\"Jason\",\"FriendName\":\"Danny\",\"FriendAge\":19}]";
var req = JsonConvert.DeserializeObject<IEnumerable<RequestModel>>(json);
var res= req.GroupBy(x=> new {x.Id,x.Name})
.Select(x=> new Result{
Name =x.Key.Name,
Id = x.Key.Id,
Friends = x.Select(z=> new Friend(){
Name = z.FriendName,
Age = z.FriendAge
}).ToArray()
});
var jsonResult = JsonConvert.SerializeObject(res);

Adding row into DataTable

How to add rows into datatable without foreach loop by reading records from csv ?
var records = File.ReadLines(FD.FileName, Encoding.UTF8).Skip(1);
//not working because datatable is not thread safe
Parallel.ForEach(records, record => dataTable.Rows.Add(record.Split(',')));
//using for each is taking aroung 13 sec for 45000 records, need a better solution than this.
foreach (var record in records)
{
dataTable.Rows.Add(record.Split(','));
}
Have you tried using a library like LINQ to CSV?
LINQ to CSV library
I have used it recently and its pretty good.
Basically you set the structure in your class like below
using LINQtoCSV;
using System;
class Product
{
[CsvColumn(Name = "ProductName", FieldIndex = 1)]
public string Name { get; set; }
[CsvColumn(FieldIndex = 2, OutputFormat = "dd MMM HH:mm:ss")]
public DateTime LaunchDate { get; set; }
[CsvColumn(FieldIndex = 3, CanBeNull = false, OutputFormat = "C")]
public decimal Price { get; set; }
[CsvColumn(FieldIndex = 4)]
public string Country { get; set; }
[CsvColumn(FieldIndex = 5)]
public string Description { get; set; }
}
There after use the below code to read the file
CsvFileDescription inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
CsvContext cc = new CsvContext();
IEnumerable<Product> products =
cc.Read<Product>("products.csv", inputFileDescription);
// Data is now available via variable products.
var productsByName =
from p in products
orderby p.Name
select new { p.Name, p.LaunchDate, p.Price, p.Description };
// or ...
foreach (Product item in products) { .... }
Let me know how it goes
I'm sure, that you don't need to display 50000 of rows at once.
Just because this is not human-readable.
Consider pagination: load first N rows, then, when user clicks "Next page" button, load next N rows, and so on.
Having this class for data row:
public class MyDataRow
{
public int Id { get; set; }
public string Name { get; set; }
}
pagination demo will be like this:
public partial class Form1 : Form
{
private const int PageSize = 10;
private readonly BindingList<MyDataRow> dataRows;
private readonly IEnumerator<string> csvLinesEnumerator;
public Form1()
{
InitializeComponent();
// start enumeration
csvLinesEnumerator = ReadLines().Skip(1).GetEnumerator();
// assign data source to DGV
dataRows = new BindingList<MyDataRow>();
dataGridView1.DataSource = dataRows;
// fetch first page
FetchNextPage();
}
private void button1_Click(object sender, EventArgs e) => FetchNextPage();
private void FetchNextPage()
{
// disable notifications
dataRows.RaiseListChangedEvents = false;
try
{
dataRows.Clear();
while (dataRows.Count < PageSize)
{
if (csvLinesEnumerator.MoveNext())
{
// parse next line and make row object from line's data
var lineItems = csvLinesEnumerator.Current.Split(',');
var row = new MyDataRow
{
Id = int.Parse(lineItems[0]),
Name = lineItems[1]
};
// add next row to the page
dataRows.Add(row);
}
else
{
break;
}
}
}
finally
{
// enable notifications and reload data source into DGV
dataRows.RaiseListChangedEvents = true;
dataRows.ResetBindings();
}
}
/// <summary>
/// This is just File.ReadLines replacement for testing purposes
/// </summary>
private IEnumerable<string> ReadLines()
{
for (var i = 0; i < 50001; i++)
{
yield return $"{i},{Guid.NewGuid()}";
}
}
}
UI:
Another option is to use DataGridView.VirtualMode, but it mostly optimized for cases, when you know the total number of rows (e.g., you can count them via SQL query), which isn't true for CSV files.

How to put multiple values in Dictionary instances using LINQ?

My Json Response is Following below:
{"d":
{"RowData":
[{"GenreId":11,"GenreName":"Musical","subjecturl":"subjecturl_1","logourl":"logourl_1"},
{"GenreId":12,"GenreName":"kids","subjecturl":"subjecturl_2","logourl":"logourl_2"},
{"GenreId":13,"GenreName":"other","subjecturl":"subjecturl_3","logourl":"logourl_3"},
{"GenreId":14,"GenreName":"Musical","subjecturl":"subjecturl_4","logourl":"logourl_4"},
{"GenreId":15,"GenreName":"Music","subjecturl":"subjecturl_5","logourl":"logourl_5"},
{"GenreId":16,"GenreName":"Faimaly","subjecturl":"subjecturl_6","logourl":"logourl_6"},
{"GenreId":17,"GenreName":"other","subjecturl":"subjecturl_7","logourl":"logourl_7"},
{"GenreId":18,"GenreName":"other","subjecturl":"subjecturl_8","logourl":"logourl_8"},
{"GenreId":19,"GenreName":"kids","subjecturl":"subjecturl_9","logourl":"logourl_9"},
{"GenreId":20,"GenreName":"Musical","subjecturl":"subjecturl_10","logourl":"logourl_10"},
{"GenreId":21,"GenreName":"other","subjecturl":"subjecturl_11","logourl":"logourl_11"}]}}
Using the above Response I tried to make like below Response :
{"rows": [{
"title": "Musical",
"items": [{"hdsubjecturl": "subjecturl_1"},{"hdsubjecturl": "subjecturl_4"},{"hdsubjecturl": "subjecturl_10"}]
},{
"title": "kids",
"items": [{"hdsubjecturl": "subjecturl_2"},{"hdsubjecturl": "subjecturl_9"}]
},{
"title": "Music",
"items": [{"hdsubjecturl": "subjecturl_5"}]
},{
"title": "other",
"items": [{"hdsubjecturl": "subjecturl_3"},{"hdsubjecturl": "subjecturl_7"},{"hdsubjecturl": "subjecturl_8"},{"hdsubjecturl": "subjecturl_11"}]
},{
"title": "Faimaly",
"items": [{"hdsubjecturl": "subjecturl_6"}]
}]
}
My Code is below :
JObject Root = JObject.Parse(jsonData["d"].ToString());
var unique = Root["RowData"].GroupBy(x => x["GenreName"]).Select(x => x.First()).ToList(); // here fetch 5 record
foreach (var un in unique)
{
var GenreName = new
{
title = un["GenreName"],
items = new
{
hdsubjecturl = "logourl"
}
};
var GenreNamereq = JsonConvert.SerializeObject(GenreName, Newtonsoft.Json.Formatting.Indented);
genstr.Append(GenreNamereq, 0, GenreNamereq.Length);
genstr.Append(",");
using (System.IO.StreamWriter file = new System.IO.StreamWriter(subdir + "\\GenreName.json"))
{
string st = genstr.ToString().Substring(0, (genstr.Length - 1));
file.WriteLine("{\n\"rows\": [\n" + st + "\n}"); //seasion number 21 terminate
file.Close();
}
}
Using above code my output is below for First Field :
{"rows":
[{
"title": "Musical",
"items": {
"hdsubjecturl": "logourl"
}
}]
}
Using below code I tried to fetch Multiple values using specific Field :
List<string> CategoryList = new List<string>();
var unique = Root["RowData"].GroupBy(x => x["GenreName"]).Select(x => x.First()).ToList(); // here fetch 8 record
foreach (var cat in unique)
{
CategoryList.Add(cat["GenreName"].ToString());
}
List<List<string>> myList = new List<List<string>>();
for (int i=0;i<CategoryList.Count();i++)
{
var results = from x in Root["RowData"]
where x["GenreName"].Value<string>() == CategoryList[i]
select x;
foreach (var token in results)
{
Console.WriteLine(token["logourl"]);
}
// myList.Add(results);
}
In the First code, I used JObject for fetching a Root node. But, using the above query it takes by default JTocken. So, I used foreach loop here.
I used Dictionary instances for JSON Creation. Using this code I successfully fetched hdsubjecturl in for loop. But, I don't know how to put multiple values in Dictionary instances. Because I get title fields only single times using a unique query and items fields inside a hdsubjetcurl is more than one. Does anyone know how it's possible?
You can group your RowData by GenreName token, then use ToDictionary method to get a result dictionary and map it to desired structure (with title and hdsubjecturl). Finally create a result object using JObject.FromObject
var json = JObject.Parse(jsonString);
var data = json["d"]?["RowData"]
.GroupBy(x => x["GenreName"], x => x["subjecturl"])
.ToDictionary(g => g.Key, g => g.ToList())
.Select(kvp => new { title = kvp.Key, items = kvp.Value.Select(x => new { hdsubjecturl = x }) });
var result = JObject.FromObject(new { rows = data });
Console.WriteLine(result);
It gives you the expected result.
Edit: according to comments, GroupBy and Select expressions should be updated to map more then one property in result title item
var data = json["d"]?["RowData"]
.GroupBy(x => x["GenreName"])
.ToDictionary(g => g.Key, g => g.ToList())
.Select(kvp => new
{
title = kvp.Key,
items = kvp.Value.Select(x => new { hdsubjecturl = x["subjecturl"], url = x["logourl"] })
});
var result = JObject.FromObject(new { rows = data });
Consider trying this code, (using Newtonsoft Json deserializer);
public partial class Root
{
public D D { get; set; }
}
public partial class D
{
public RowDatum[] RowData { get; set; }
}
public partial class RowDatum
{
public long GenreId { get; set; }
public string GenreName { get; set; }
public string Subjecturl { get; set; }
public string Logourl { get; set; }
}
public partial class Response
{
public Row[] Rows { get; set; }
}
public partial class Row
{
public string Title { get; set; }
public Item[] Items { get; set; }
}
public partial class Item
{
public string Hdsubjecturl { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var json =
#"{""d"":{""RowData"":[{""GenreId"":11,""GenreName"":""Musical"",""subjecturl"":""subjecturl_1"",""logourl"":""logourl_1""},{""GenreId"":12,""GenreName"":""kids"",""subjecturl"":""subjecturl_2"",""logourl"":""logourl_2""},{""GenreId"":13,""GenreName"":""other"",""subjecturl"":""subjecturl_3"",""logourl"":""logourl_3""},{""GenreId"":14,""GenreName"":""Musical"",""subjecturl"":""subjecturl_4"",""logourl"":""logourl_4""},{""GenreId"":15,""GenreName"":""Music"",""subjecturl"":""subjecturl_5"",""logourl"":""logourl_5""},{""GenreId"":16,""GenreName"":""Faimaly"",""subjecturl"":""subjecturl_6"",""logourl"":""logourl_6""},{""GenreId"":17,""GenreName"":""other"",""subjecturl"":""subjecturl_7"",""logourl"":""logourl_7""},{""GenreId"":18,""GenreName"":""other"",""subjecturl"":""subjecturl_8"",""logourl"":""logourl_8""},{""GenreId"":19,""GenreName"":""kids"",""subjecturl"":""subjecturl_9"",""logourl"":""logourl_9""},{""GenreId"":20,""GenreName"":""Musical"",""subjecturl"":""subjecturl_10"",""logourl"":""logourl_10""},{""GenreId"":21,""GenreName"":""other"",""subjecturl"":""subjecturl_11"",""logourl"":""logourl_11""}]}}";
var root = JsonConvert.DeserializeObject<Root>(json);
var rows = root.D.RowData.ToLookup(d => d.GenreName)
.Select(g => new Row()
{
Title = g.Key,
Items = g.ToList().Select(rd => new Item() {Hdsubjecturl = rd.Logourl}).ToArray()
}).ToArray();
var response = new Response()
{
Rows = rows
}; // reponse is the type of Json Response you wanted to achieve
Console.WriteLine();
}
}

Calculating the average of a column in a CSV file using linq c#

I am really new to c# but I really want to start using linq to extract simple information from excel spreadsheets.
I feel quite embarrassed to ask this, but I can't seem to find a solution. Basically, all I want is find the average of the amount of donations within a CSV file.
This is following code so far:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CSharpTest
{
class Program
{
public string Donor { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public string Charity { get; set; }
static void Main(string[] args)
{
{
var file = "C:\\Users\\user\\Desktop\\Donations.csv".AsFile();
File.ReadAllLines(file).Select(x => x.Split('\n')).Average(x => x.Count());
}
}
}
The thing is I know this is wrong as I only want the values in Amount. For something like this I am sure I should be using GroupBy(), however I can't seem to extract the public class Amount. I would be ever so grateful if someone could point me in the right direction please. Many thanks.
Creating an object model to hold the data is a good start
public class Donation {
public string Donor { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public string Charity { get; set; }
}
Next you want to parse the data from the CSV file.
Something like CSVHelper would help in parsing the data into usable objects.
var textReader = new StreamReader("C:\\Users\\user\\Desktop\\Donations.csv");
var csv = new CsvReader( textReader );
var records = csv.GetRecords<Donation>();
From there calculating the average using LINQ is a simple matter of calling the extension method on the parsed collection.
var average = records.Average(_ => _.Amount);
If external Lib like CSVHelper from Nkosi's answer is not possible you can keep the same principle but parse it by hand like:
public class Model
{
public int Id { get; set; }
public string Donor { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public string Charity { get; set; }
}
string csv = File.ReadAllText(file);
//skip(1), for hearder
var lines = csv.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries).Skip(1);
List<Model> models = new List<Model>();
int id=1;
foreach (var item in lines)
{
var values = item.Split(',');
if(values.Count()!= 4) continue;//error loging
var model = new Model
{
Id = id,
Donor = values[0],
Date = DateTime.Parse(values[1]),
Amount = Decimal.Parse(values[2]),
Charity = values[3]
};
models.Add(model);
id++;
}
And now you can linq easly:
var result = models.Average(x=> x.Amount);
And for Average per person
var avgPerPerson = models
.GroupBy(x=> x.Donor)
.Select(g=> new {
Donor = g.Key,
Average = g.Average(c => c.Amount)
});
var total = 0.0d;
foreach (var line in File.ReadLines(//FilePath))
{
var lineArr = line.Split(',');
double lineDonation;
if (double.TryParse(lineArr[2])
total += lineDonation;
}
You can Microsoft Excel package "Microsoft.Office.Interop.Excel". you can easily download it from Nuget:
static void Main(string[] args)
{
Microsoft.Office.Interop.Excel.Application xlsApp = new Microsoft.Office.Interop.Excel.Application();
if (xlsApp == null)
{
//Any message
}
Workbook wb = xlsApp.Workbooks.Open("C:\\Users\\310231566\\Downloads\\main.xlsx",
0, true, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true);
Sheets sheets = wb.Worksheets;
Worksheet ws = (Worksheet)sheets.get_Item(1);
Range firstColumn = ws.UsedRange.Columns[1];
System.Array myvalues = (System.Array)firstColumn.Cells.Value;
string[] strArray = myvalues.OfType<object>().Select(o => o.ToString()).ToArray();
int j = 0;
int avg = 0;
int[] intArray = new int[strArray.Length-1];
for (int i = 1; i < strArray.Length; i++)
{
intArray[j] = int.Parse(strArray[i]);
avg = avg + intArray[j];
j++;
}
avg = avg/intArray.Length;
}
Average amount per donor onliner, with no failsafe :
var avg = File
.ReadAllLines(file)
.Skip(1)
.Select(x => x.Split(','))
.Select((x,i) => new {
Donor = values[0],
Amount = Decimal.Parse(values[2])
})
.GroupBy(x=> x.Donor)
.Select(g=> new {
Donor = g.Key,
AverageAmount = g.Average(c => c.Amount)
});

Converting objects with string[] properties to CSV or Excel

Is there any library out there that can serialize objects with array properties to .csv?
Let's say I have this model:
public class Product
{
public string ProductName { get; set; }
public int InStock { get; set; }
public double Price { get; set; }
...
public string[] AvailableVariants { get; set; }
}
Would something like that be possible to do?
Edit: I need to present some data in a csv/excel format. The thing is, I'm not sure if there is a simple way of achieving what I want with CSV serialization libraries or if I should rather focus on writing an Excel native file.
An example of result I'm looking for:
Product Name In Stock Price Variants
ABC 241 200 Normal
CAB 300 300 Normal
Red
Blue
CBA 125 100 Normal
White
Awesome
Red
ACB 606 75 Normal
Small
Large
X-Large
What would be the most efficient way to do this?
I'm not aware of any libraries that will do this, here's a console example of how I'd approach writing/reading from a CSV:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace TestingProduct
{
class TestingProduct
{
public class Product
{
public string ProductName { get; set; }
public int InStock { get; set; }
public double Price { get; set; }
public string[] AvailableVariants { get; set; }
public override string ToString() => $"{ProductName},{InStock},{Price}{(AvailableVariants?.Length > 0 ? "," + string.Join(",", AvailableVariants) : "")}";
public static Product Parse(string csvRow)
{
var fields = csvRow.Split(',');
return new Product
{
ProductName = fields[0],
InStock = Convert.ToInt32(fields[1]),
Price= Convert.ToDouble(fields[2]),
AvailableVariants = fields.Skip(3).ToArray()
};
}
}
static void Main()
{
var prod1 = new Product
{
ProductName = "test1",
InStock= 2,
Price = 3,
AvailableVariants = new string[]{ "variant1", "variant2" }
};
var filepath = #"C:\temp\test.csv";
File.WriteAllText(filepath, prod1.ToString());
var parsedRow = File.ReadAllText(filepath);
var parsedProduct = Product.Parse(parsedRow);
Console.WriteLine(parsedProduct);
var noVariants = new Product
{
ProductName = "noVariants",
InStock = 10,
Price = 10
};
var prod3 = new Product
{
ProductName = "test2",
InStock= 5,
Price = 5,
AvailableVariants = new string[] { "variant3", "variant4" }
};
var filepath2 = #"C:\temp\test2.csv";
var productList = new List<Product> { parsedProduct, prod3, noVariants };
File.WriteAllText(filepath2, string.Join("\r\n", productList.Select(x => x.ToString())));
var csvRows = File.ReadAllText(filepath2);
var newProductList = new List<Product>();
foreach (var csvRow in csvRows.Split(new string[] { "\r\n" }, StringSplitOptions.None))
{
newProductList.Add(Product.Parse(csvRow));
}
newProductList.ForEach(Console.WriteLine);
Console.ReadKey();
}
}
}
This code will work with a class that has a single object array property. Do you need something that can handle an object with multiple array properties?
I have written some kind of library to write csv files, have a look:
public static class CsvSerializer
{
public static bool Serialize<T>(string path, IList<T> data, string delimiter = ";")
{
var csvBuilder = new StringBuilder();
var dataType = typeof(T);
var properties = dataType.GetProperties()
.Where(prop => prop.GetCustomAttribute(typeof(CsvSerialize)) == null);
//write header
foreach (var property in properties)
{
csvBuilder.Append(property.Name);
if (property != properties.Last())
{
csvBuilder.Append(delimiter);
}
}
csvBuilder.Append("\n");
//data
foreach (var dataElement in data)
{
foreach (var property in properties)
{
csvBuilder.Append(property.GetValue(dataElement));
if (property != properties.Last())
{
csvBuilder.Append(delimiter);
}
}
csvBuilder.Append("\n");
}
File.WriteAllText(path, csvBuilder.ToString());
return true;
}
}
public class CsvSerialize : Attribute
{
}
Lets pretend you want to serialize following class:
public class MyDataClass
{
[CsvSerialize]
public string Item1 {get; set;}
[CsvSerialize]
public string Item2 {get; set;}
}
Then just do:
public void SerializeData(IList<MyDataClass> data)
{
CsvSerializer.Serialize("C:\\test.csv", data);
}
It takes a IList of your class and writes a csv.
It cant serialize arrays but that would be easy to implement.

Categories

Resources