How can I code in wpf -xaml (C#) to read a specific line in a .csv File.
Every button on the Periodic table I made goes to a new window which shows in a listview the specific things about it. But then my question how to do that?
public class Atomic
{
public string Group { get; set; }
public string Period { get; set; }
public string Block { get; set; }
public string Atomicnumber { get; set; }
public string Stateat { get; set; }
public string Electronconfiguration { get; set; }
public string ChemspiderID { get; set; }
public Atomic(string group, string period, string block, string atomicnumber, string stateat, string electronconfiguration, string chemspiderID)
{
Group = group;
Period = period;
Block= block;
Atomicnumber = atomicnumber;
Stateat = stateat;
Electronconfiguration = electronconfiguration;
ChemspiderID = chemspiderID;
}
}
public IEnumerable<Atomic> ReadCSV(string fileName)
{
// We change file extension here to make sure it's a .csv file.
// TODO: Error checking.
string[] lines = File.ReadAllLines(System.IO.Path.ChangeExtension(fileName, ".csv"));
// lines.Select allows me to project each line as a Person.
// This will give me an IEnumerable<Person> back.
return lines.Select(line =>
{
string[] data = line.Split(';');
// We return a person with the data in order.
return new Atomic(data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
});
}
If you want to read a specific line you could do the following.
public Atomic ReadCSV(string fileName, int lineIndex)
{
return File.ReadLines(System.IO.Path.ChangeExtension(fileName, ".csv"))
.Skip(lineIndex)
.Select(line => line.Split(';'))
.Select(data => new Atomic(data[0], data[1], data[2], data[3], data[4], data[5], data[6]))
.FirstOrDefault();
}
This will read the first lineNumber + 1 lines of the file take the last line read and create your Atomic object from that line. If there are not enough lines it will return a null value. If you prefer a one based index just change .Skip(lineIndex) to .Skip(lineIndex - 1).
Related
I have my variables class with constructor
public class Gdf2Lines
{
public string line { get; set; }
public int linenumber { get; set; }
public string columnNumber { get; set; }
public string columnName { get; set; }
public Gdf2Lines()
{
line = "";
linenumber = -1;
columnNumber = ""; // prefer to keep as the string read from the text source
columnName = "";
}
}
I have my class that creates of list of the above class and populates the variables within for each line from a file
class GDF2
{
Gdf2Lines Data = new Gdf2Lines();
List<Gdf2Lines> gdf2 = new List<Gdf2Lines>();
public GDF2(string[] arrFile)
{
int count = 0;
foreach (String line in arrFile)
{
Data.line = line;
Data.linenumber = count;
Data.columnNumber = GetColumnNumber(line);
Data.columnName = GetColumnName(line);
count++;
gdf2.Add(Data);
}
}
}
I know a "normal" list can be joined into a string by:
String.Join(Environment.Newline.ToString(), List);
But is there an equally easy way to join one of the (sub) variables within my list, such as
String.Join(",", gdf2.columnName);
Currently I am using a for loop.
Something like this should work:
String.Join(",", gdf2.Select(x => x.columnName));
This uses LINQ to extract a list of columnName values from the list of Gdf2Line.
Basic Gist: User browses to CSV, app reads CSV, parses does some calcs and then spits out a new csv. This is a windows Form app using c# flavoured .net.
CSV File being Tested:
Position,Title3,Title1,Title2,Title4,Title5,,
1,P-D3101A,NAME 1,175,282.9280381,1 x 30 x 120
2,P-D3103A,NAME 2,37.2,60.14241724,30 x 16
3,P-D3102A,NAME 3,29.8,48.17860306,30 x 10
4,P-D2301A,NAME 4,35,56.58560762,30 x 16
5,P-D1201A,NAME 5,38,61.43580256,30 x 16
6,P-D2301D,NAME 6,32,51.73541268,30 x 16
7,A-D0636,NAME 7,8.5,13.74221899,30 x 1.5
Have a class:
class Equipment
{
public string Title1 { get; set; }
public double Title2 { get; set; }
public string Title3 { get; set; }
}
and a parser (thanks very much to SO community) :
static IList<Equipment> Parse(string[] input)
{
var result = new List<Equipment>();
var header = input[0].Split(',').Select(t => t.Trim().ToLower()).ToList();
var title1Loc = GetIndexOf(header, "title1");
var title2Loc = GetIndexOf(header, "title2");
var title3Loc = GetIndexOf(header, "title3");
foreach (var s in input.Skip(1))
{
var line = s.Split(',');
result.Add(new Equipment
{
Title1 = line[title1Loc].Trim(),
Title2 = double.Parse(line[title2Loc]),
Title3 = line[title3Loc].Trim(),
});
}
return result;
}
static int GetIndexOf(IList<string> input, params string[] needles)
{
return Array.FindIndex(input.ToArray(), needles.Contains);
}
and a couple of buttons, one is to get the file and save its file path in the string referenceFile , the other is to parse the data:
private void button2_Click(object sender, EventArgs e)
{
string[] data = File.ReadAllLines(referenceFile);
MessageBox.Show(string.Join(Environment.NewLine, data), "Your CSV");
}
Ultimately I want to produce a new CSV File, which I can although its blank, so to check what its getting from the parsed data I used a message box which displays:
MyProject.Form1+Equipment
repeated 7 times on new lines. So it is correctly going over my 7 line file, however not actually generating what I want. Any glaring errors I cant see?
You will need to override the ToString method of to Equipment class to get the desired output which dictates that how the string representation of your type should look like.
Here is how it can look like as an example:
class Equipment
{
public string Title1 { get; set; }
public double Title2 { get; set; }
public string Title3 { get; set; }
public override string ToString()
{
return $"{Title1},{Title2},{Title3}";
}
}
I have a csv consisting of many columns. From that csv I have to select only few required columns.
The code I have written is
for (int i = 0; i < lineCount; i++)
{
var line = str.ReadLine();
if (line != null)
{
var values = line.Split(',');
dataInformation.Add(new DataInformation
{
timestamp_iso = values[3],
last_attributed_touch_data_tilde_campaign = values[9],
last_attributed_touch_data_tilde_channel = values[11],
last_attributed_touch_data_tilde_feature = values[12],
last_attributed_touch_data_tilde_ad_set_name = values[19],
user_data_platform = values[69],
user_data_aaid = values[70],
user_data_idfa = values[71],
user_data_idfv = values[72]
});
}
}
I am getting wrong values while using this. Is there any other approach to retrieve the values using the column names instead of column numbers.
The Data Information is a class
public class DataInformation
{
public string timestamp_iso { get; set; }
public string last_attributed_touch_data_tilde_campaign { get; set; }
public string last_attributed_touch_data_tilde_channel { get; set; }
public string last_attributed_touch_data_tilde_feature { get; set; }
public string last_attributed_touch_data_tilde_ad_set_name { get; set; }
public string user_data_platform { get; set; }
public string user_data_aaid { get; set; }
public string user_data_idfa { get; set; }
public string user_data_idfv { get; set; }
}
Please help me on this.
I recommend using a library to deal with CSV format. CsvHelper is a good one. It allows accessing fields by column name:
csv.Read();
var field = csv["HeaderName"];
CSV format may look simple, but there are a few corner cases (like quotes), so it is better to use an existing solution.
I have used the below code to get all the records of the type DataInformation.
using (TextReader fileReader = File.OpenText(FileName))
{
var csv = new CsvReader(fileReader);
dataInformation = csv.GetRecords<DataInformation>().ToList();
}
And after that I have used the below code to get the required columns.
using (TextWriter writer = new StreamWriter(ConfigurationManager.AppSettings["downloadFilePath"] + ConfigurationManager.AppSettings["fileName"] + date + ConfigurationManager.AppSettings["csvExtension"].ToString()))
{
using (var csv = new CsvWriter(TextWriter.Synchronized(writer)))
{
csv.WriteHeader(typeof(DataInformation));
csv.NextRecord();
csv.WriteRecords(dataInformation);
}
}
It works for me.
I am trying to use this for each loop to iterate through this array, and sum up the elements, 12, 10, 8, 7, and 6, when element 0 is not different (position.account), using control break logic,
This is furthering on a question I had earlier, but I can't seem to figure out how to do this logically.
static void Main(string[] args)
{
String path = #"C:\Users\jhochbau\documents\visual studio 2015\Projects\CsvReader\CsvReader\Position_2016_02_25.0415.csv";
//Adding lines read into a string[];
string[] lines = File.ReadAllLines(path);
foreach(string line in lines)
{
Positions position = new Positions();
string[] parsedLine = line.Split(',');
position.account = parsedLine[0];
position.settleMM = parsedLine[10];
position.open = parsedLine[6];
position.buy = parsedLine[7];
position.sell = parsedLine[8];
position.underlying = parsedLine[12];
//Need to convert these to an int.
//for each iteration through the loop where string[0] is already existing
//I want to have sum = sum + string[10]
}
Console.Read();
}
public class Positions
{
public string account { get; set; }
public string symbol { get; set; }
public string prevClose { get; set; }
public string curPrx { get; set; }
public string settlePX { get; set; }
public string Mult { get; set; }
public string open { get; set; }
public string buy { get; set; }
public string sell { get; set; }
public string netMM { get; set; }
public string settleMM { get; set; }
public string settleDay { get; set; }
public string underlying { get; set; }
}
Further to my comment, you could do something like this:
// store the accounts inside this dictionary
var accounts = new Dictionary<string, Positions>();
foreach(string line in lines)
{
Positions position = new Positions();
string[] parsedLine = line.Split(',');
position.account = parsedLine[0];
...
Positions existingAccount;
// if the account already exists in the dictionary
if (accounts.TryGetValue(position.account, out existingAccount)) {
existingAccount.buy += position.buy;
// do updating logic here
} else {
accounts.add(position.account, position);
// otherwise add it as a new element
}
}
Alternatively, you could go for Linq:
File.ReadLines(path)
.Select( line => new Position(line) )
.GroupBy( position => position.account )
.Select( group => new { Account = group.Key,
Sum = group.Select( position => position.settleMM ).Sum() } );
public class Earthquake
{
public double Magnitude { get; set; }
public string Location { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double depth { get; set; }
public DateTime date { get; set; }
public string EventID { get; set; }
public string URL { get; set; }
public Earthquake()
: this(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)
{ }
public Earthquake(string magna, string locate, string lat, string longi, string dept, string dat, string Event, string website)
{
Magnitude = Convert.ToDouble(magna);
Location = locate;
Latitude = Convert.ToDouble(lat);
Longitude = Convert.ToDouble(longi);
depth = Convert.ToDouble(dept);
date = Convert.ToDateTime(dat);
EventID = Event;
URL = website;
}
}
public void GetData()
{
string[] text = File.ReadAllLines(#"Earthquakes.csv");
Earthquake[] data = new Earthquake[1];
foreach (string line in text)
{
string[] myColumns = line.Split(',');
Earthquake[] earth = new Earthquake[myColumns[0], myColumns[1], myColumns[2], myColumns[3], myColumns[4], myColumns[5], myColumns[6], myColumns[7]];
data[i] = earth[i];
i++;
}
}
Ignore commented parts I have those under control. The problem I am having is getting the data from the csv file into the Earthquake Array. I am getting syntax errors, and I know why, it's because the data type isn't correct, but I honestly cannot figure out how to fix it.
Also if you notice I am trying to use bubble sort and since there is no definition for "compare" for double, what do I use instead?
If your reading from CSV file you probably have to remove white space from the split values.
Try adding .Trim() to your column variables
myColumns[0].Trim()
if your looking to sort yor array consider using System.Linq
eg:
var byMag = earthQuakes.OrderBy(e => e.Magnitude);
Looking at your code you posted, GetData() will not work.
Try returning a list or Enumerable
public IEnumerable<Earthquake> GetData(string filename)
{
string[] text = File.ReadAllLines(filename);
foreach (string line in text)
{
string[] myColumns = line.Split(',');
yield return new Earthquake(myColumns[0].Trim(), myColumns[1].Trim(), myColumns[2].Trim(), myColumns[3].Trim(), myColumns[4].Trim(), myColumns[5].Trim(), myColumns[6].Trim(), myColumns[7].Trim());
}
}
Usage:
var earthquakes = GetData(#"Earthquakes.csv");