Read lines of data from CSV then display data - c#

I have to read info from a txt file, store it in a manner (array or list), then display the data. Program must include at least one additional class.
I've hit a wall and can't progress.
string, string, double, string
name,badge,salary,position
name,badge,salary,position
name,badge,salary,position
I'm sorry and I know the code below is disastrous but I'm at a loss and am running out of time.
namespace Employees
{
class Program
{
static void Main()
{
IndividualInfo collect = new IndividualInfo();
greeting();
collect.ReadInfo();
next();
for (int i = 0; i < 5; i++)
{
displayInfo(i);
}
exit();
void greeting()
{
Console.WriteLine("\nWelcome to the Software Development Company\n");
}
void next()
{
Console.WriteLine("\n*Press enter key to display information . . . *");
Console.Read();
}
void displayInfo(int i)
{
Console.WriteLine($"\nSoftware Developer {i + 1} Information:");
Console.WriteLine($"\nName:\t\t\t{collect.nameList[i]}");
}
void exit()
{
Console.WriteLine("\n\n*Press enter key to exit . . . *");
Console.Read();
Console.Read();
}
}
}
}
class IndividualInfo
{
public string Name { get; set; }
//public string Badge{ get; set; }
//public string Position{ get; set; }
//public string Salary{ get; set; }
public void ReadInfo()
{
int i = 0;
string inputLine;
string[] eachLine = new string[4];
string[,] info = new string[5, 4]; // 5 developers, 4x info each
StreamReader file = new StreamReader("data.txt");
while ((inputLine = file.ReadLine()) != null)
{
eachLine = inputLine.Split(',');
for (int x = 0; x < 5; x++)
{
eachLine[x] = info[i, x];
x++;
}
i++;
}
string name = info[i, 0];
string badge = info[i, 1];
string position = info[i, 2];
double salary = Double.Parse(info[i, 3]);
}
public List<string> nameList = new List<string>();
}
So far I think I can collect it with a two-dimensional array, but a List(s) would be better. Also, the code I've posted up there won't run because I can't yet figure out a way to get it to display. Which is why I'm here.

using System.IO;
static void Main(string[] args)
{
using(var reader = new StreamReader(#"C:\test.csv"))
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
listA.Add(values[0]);
listB.Add(values[1]);
}
}
}
https://www.rfc-editor.org/rfc/rfc4180
or
using Microsoft.VisualBasic.FileIO;
var path = #"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
// Skip the row with the column names
csvParser.ReadLine();
while (!csvParser.EndOfData)
{
// Read current line fields, pointer moves to the next line.
string[] fields = csvParser.ReadFields();
string Name = fields[0];
string Address = fields[1];
}
}
http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
or
LINQ way:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^Wrong - Edit by Nick
It appears the original answerer was attempting to populate csv with a 2 dimensional array - an array containing arrays. Each item in the first array contains an array representing that line number with each item in the nested array containing the data for that specific column.
var csv = from line in lines
select (line.Split(',')).ToArray();
This question was fully addressed here:
Reading CSV file and storing values into an array

Related

C# Read file, split at ; write in array

so I have a file like this:
1;2;5
1;3;3
1;4;3
1;5;1
1;6;0
and I want every number as easy accassible as possibe
so I thought multi dimentional array
that's the idea so far:
System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Users\Hisfantor\Desktop\transport.txt");
int count = 0;
string linee;
string line;
string[] extract;
while ((linee = file.ReadLine()) != null)
{
count++;
}
textBox1.Text = Convert.ToString(count);
double[,] destinations = new double[(int)count, 3];
for (int i = 0; i < count; i++)
{
line = file.ReadLine();
extract = line.Split(';');
destinations[i, 1] = Convert.ToDouble(extract[0]);
destinations[i, 2] = Convert.ToDouble(extract[1]);
destinations[i, 3] = Convert.ToDouble(extract[2]);
listBox1.Items.Add(destinations[i, 1]);
}
file.Close();
I tried different things, but never get anything in the listbox(just for testing)
Try this:
using System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Users\Hisfantor\Desktop\transport.txt");
int count = 0;
string line;
string[] extract;
while ((line = file.ReadLine()) != null)
{
extract = line.Split(';');
var lineValue = new LineValue()
{
Col1 = Convert.ToDouble(extract[0]),
Col2 = Convert.ToDouble(extract[1]),
Col3 = Convert.ToDouble(extract[2]),
};
listBox1.Items.Add(lineValue);
count++;
}
textBox1.Text = Convert.ToString(count);
public class LineValue
{
public double Col1 { get; set; }
public double Col2 { get; set; }
public double Col3 { get; set; }
public override string ToString() => $"{Col1};{Col2};{Col3}";
}
I suggest jagged array, i.e. array of array double[][] instead of 2D one (double[,]). Then you can query the file with a help of Linq:
using System.Linq;
...
double[][] destinations = File
.ReadLines(#"C:\Users\Hisfantor\Desktop\transport.txt")
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select(line => line
.Split(';')
.Select(item => double.Parse(item))
.ToArray())
.ToArray();
foreach (var array in destinations)
listBox1.Items.Add(array[1]);
This is how I would approach it.
class Item
{
public int Value1 { get; set; }
public int Value2 { get; set; }
public int Value3 { get; set; }
}
string line;
List<Item> items = new List<Item>();
using (StreamReader reader = new StreamReader(path))
{
while ((line = reader.ReadLine()) != null)
{
string[] tokens = line.Split(';');
if (tokens.Length == 3)
{
int value;
Item item = new Item();
item.Value1 = int.TryParse(tokens[0], out value) ? value : 0;
item.Value2 = int.TryParse(tokens[1], out value) ? value : 0;
item.Value3 = int.TryParse(tokens[2], out value) ? value : 0;
items.Add(item);
}
}
}
This code reads a line at a time and populates a list of Items as it reads them. It includes error checking to avoid unexpected exceptions due to invalid inputs.
Also, you should wrap StreamReader in a using block to ensure it cleans up in a timely manner, even if an exception exits your method prematurely.

binary search in a sorted list in c#

I am retrieving client id\ drum id from a file and storing them in a list.
then taking the client id and storing it in another list.
I need to display the client id that the user specifies (input_id) on a Datagrid.
I need to get all the occurrences of this specific id using binary search.
the file is already sorted.
I need first to find the occurrences of input_id in id_list.
The question is: how to find all the occurrences of input_id in the sorted list id_list using binary search?
using(StreamReader sr= new StreamReader(path))
{
List<string> id_list = new List<string>();
List<string> all_list= new List<string>();
List<int> indexes = new List<int>();
string line = sr.ReadLine();
line = sr.ReadLine();
while (line != null)
{
all_list.Add(line);
string[] break1 = line.Split('/');
id_list.Add(break1[0]);
line = sr.ReadLine();
}
}
string input_id = textBox1.Text;
Data in the file:
client id/drum id
-----------------
123/321
231/3213
321/213123 ...
If the requirement was to use binary search I would create a custom class with a comparer, and then find an element and loop forward/backward to get any other elements. Like:
static void Main(string[] args
{
var path = #"file path...";
// read all the Ids from the file.
var id_list = File.ReadLines(path).Select(x => new Drum
{
ClientId = x.Split('/').First(),
DrumId = x.Split('/').Last()
}).OrderBy(o => o.ClientId).ToList();
var find = new Drum { ClientId = "231" };
var index = id_list.BinarySearch(find, new DrumComparer());
if (index != -1)
{
List<Drum> matches = new List<Drum>();
matches.Add(id_list[index]);
//get previous matches
for (int i = index - 1; i > 0; i--)
{
if (id_list[i].ClientId == find.ClientId)
matches.Add(id_list[i]);
else
break;
}
//get forward matches
for (int i = index + 1; i < id_list.Count; i++)
{
if (id_list[i].ClientId == find.ClientId)
matches.Add(id_list[i]);
else
break;
}
}
}
public class Drum
{
public string DrumId { get; set; }
public string ClientId { get; set; }
}
public class DrumComparer : Comparer<Drum>
{
public override int Compare(Drum x, Drum y) =>
x.ClientId.CompareTo(y.ClientId);
}
If i understand you question right then this should be a simple where stats.
// read all the Ids from the file.
var Id_list = File.ReadLines(path).Select(x => new {
ClientId = x.Split('/').First(),
DrumId = x.Split('/').Last()
}).ToList();
var foundIds = Id_list.Where(x => x.ClientId == input_id);

read CSV file into a List of strings and then loop to identify an item

I'm just learning Windows Forms with C# and I'm having a lot of trouble rewriting my Console app into a window forms app. Here is my code in the Console App:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
const string FILENAME = #"C:\Users\annage\Desktop\SCHOOL\POS409\data.txt"; //path for CSV file
List<List<string>> EmployeesInfo = new List<List<string>>();
string inputLine = "";
StreamReader reader = new StreamReader(FILENAME);
int whileLoopRan = 0;
while ((inputLine = reader.ReadLine()) != null) //enters items into array
{
if (whileLoopRan == 0)
{
whileLoopRan++;
continue;
}
whileLoopRan = 1;
List<string> inputArray = inputLine.Split(new char[] { ',' }).ToList();//remove extra spaces
inputArray = inputArray.Select(x => x.Trim()).ToList();
EmployeesInfo.Add(inputArray);
}
List<EmployeeTaxes> EmployeeList = new List<EmployeeTaxes>();
foreach (List<string> EmployeeInfo in EmployeesInfo)
{
String employeeType;
employeeType = EmployeeInfo[5];
EmployeeTaxes employeeTaxType = new EmployeeTaxes();
employeeTaxType.GrossPay = double.Parse(EmployeeInfo[3]);
if (employeeType == ("W2"))
{
double taxes;
taxes = .07;
employeeTaxType.taxes = double.Parse(EmployeeInfo[3]) * .07;
employeeTaxType.totaltaxes = employeeTaxType.taxes * 12;
}
else if (employeeType == ("1099"))
{
}
EmployeeList.Add(employeeTaxType);
}
DisplayData(EmployeeList, EmployeesInfo);
Console.ReadLine();
}
private void DisplayData(List<EmployeeTaxes> employeeList, List<List<string>> employeesInfo)
{
for (int i = 0; i < employeeList.Count; i++)
{
List<string> Row = employeesInfo[i];
string fullName = Row[0];
string address = Row[1];
string employeeType = Row[5];
string developerType = Row[6];
EmployeeTaxes taxRow = employeeList[i];
double grossPay = taxRow.GrossPay;
double taxes = taxRow.taxes;
double totalGrossPay = taxRow.TotalGrossPay();
double annualTaxes = taxRow.totaltaxes;
double netPay = taxRow.Netpay();
Console.WriteLine("Welcome, !", fullName); // shows greeting and users name
Console.WriteLine("Address: ", address); //shows address entered
Console.WriteLine("Gross Pay: $", grossPay); // Shows gross pay entered
Console.WriteLine("Employee Type: ", employeeType);
Console.WriteLine("Monthly taxes are 7%"); ("Monthly Taxes Paid are: $" + taxes.ToString("N2")); // calculated the taxes paid monthly
Console.WriteLine("Annual Gross Pay: $" + totalGrossPay.ToString("N2")); // calulates gross pay * 12months
Console.WriteLine("Annual Taxes Paid: $" + annualTaxes.ToString("N2")); // calulates taxes * 12months
Console.WriteLine("NetPay: $" + netPay.ToString("N2"));
Console.WriteLine("Developer Type: ", developerType);
}
}
}
I am reading from a CSV .txt file and then I add it to a list of strings and I search for the "employee type" and then based on that value I loop it to do a calculation and then print out all the values.
I was able to read the csv file into a textbox in windows form, but I cannot figure out how to loop it and read the specific value and then continue with my calculation.
here is what I have for my console windows form:
public Form1()
{
InitializeComponent();
this.listBox3.SelectionMode = SelectionMode.MultiSimple;
ReadingCSVFile();
}
public void ReadingCSVFile()
{
List<List<string>> EmployeesInfo = new List<List<string>>();
string inputLine = "";
using (StreamReader sr = new StreamReader(#"C:\Users\annage\Desktop\SCHOOL\POS409\data.txt"))
{
string line;
while ((line = sr.ReadLine()) != null)
listBox3.Items.Add(line);
List<string> inputArray = inputLine.Split(new char[] { ',' }).ToList();
inputArray = inputArray.Select(x => x.Trim()).ToList();
EmployeesInfo.Add(inputArray);
}
}
private void DisplayData(List<EmployeeTaxes> employeeList, List<List<string>> EmployeesInfo)
{
for (int i = 0; i < employeeList.Count; i++)
{
List<string> Row = EmployeesInfo[i];
string fullName = Row[0];
string address = Row[1];
string employeeType = Row[5];
string developerType = Row[6];
EmployeeTaxes taxRow = employeeList[i];
double grossPay = taxRow.GrossPay;
double taxes = taxRow.taxes;
double totalGrossPay = taxRow.TotalGrossPay();
double annualTaxes = taxRow.totaltaxes;
double netPay = taxRow.Netpay();
}
}
Where can I add my loop? I tried using as much of my code in both formats, but I know console.writeline needs to be changed for windows form, but I haven't gotten that far yet.
Any assistance would be very much appreciated.
First of all it is easier to use Lambda Expressions.
So your code would look like this:
public void Test()
{
List<string> myList = new List<string>();
using (var reader = new StreamReader(#"2018-03-16.csv"))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
foreach (string item in values)
{
myList.Add(item);
}
}
}
this.FindItem(myList);
}
private void FindItem(List<string> myList)
{
// if you want the value
var match = myList.FirstOrDefault(stringToCheck => stringToCheck.Equals("your item to check"));
// if you just want to check if it exists
var match2 = myList.Any(stringToCheck => stringToCheck.Equals("your item to check"));
}

Combine multiple lines into 1 string with stream reader

I have a decently sized file (95K lines) that i need to parse through. For the following sample data...
<FIPS>10440<STATE>AL<WFO>BMX
8 32.319 32.316 -86.484 -86.487 32.316 -86.484
32.316 -86.484
102 32.501 31.965 -85.919 -86.497 32.496 -86.248
32.448 -86.181 32.432 -86.189 32.433 -86.125 32.417 -86.116
32.406 -86.049 32.419 -86.023 32.337 -85.991 32.333 -85.969
32.276 -85.919 32.271 -85.986 32.250 -85.999 31.968 -85.995
31.965 -86.302 32.052 -86.307 32.051 -86.406 32.245 -86.410
32.276 -86.484 32.302 -86.491 32.332 -86.475 32.344 -86.497
32.364 -86.492 32.378 -86.463 32.405 -86.460 32.414 -86.396
32.427 -86.398 32.433 -86.350 32.412 -86.310 32.441 -86.325
32.487 -86.314 32.473 -86.288 32.488 -86.260 32.501 -86.263
32.496 -86.248
What I need to do is read from one FIPS to the next FIPS and combine the lines within each group into one giant line like the following...
<FIPS>10440<STATE>AL<WFO>BMX 8 32.319 32.316 -86.484 -86.487 32.316 -86.484 32.316 -86.484...
<FIPS>10440<STATE>AL<WFO>BMX 102 32.501 31.965 -85.919 -86.497 32.496 -86.248 32.448 -86.181...
I currently have the following code (about my 6th variation for the day). What am I missing?
using (var reader = new StreamReader(winterBoundsPath))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine().Trim();
if (!Char.IsLetter(line[0]))
{
if (line.Contains("<FIPS>"))
{
var lineReplace = line.Replace('<', ' ').Replace('>', ' ');
string[] rawData = lineReplace.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
temp = new WinterJsonModel
{
FIPS = rawData[1],
State = rawData[3],
Center = rawData[5],
polyCoords = new List<polyCoordsJsonData>()
};
}
else
{
string[] rawData2 = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (rawData2.Count() > 1)
{
allValues.Add(listPointValue);
listPointValue = new List<string>();
}
// Add values to line
foreach (string value in rawData2)
{
listPointValue.Add(value);
}
}
}
}
reader.Close();
}
Judging from the sample you've given, the line breaks are CRLF characters. This means you really only need to know two things.
1. If the line contains "FIPS" as a string literal enclosed as a tag
2. if you've reached the end of a line that has a carriage return.
I'm going to ignore the JSON bit for now, because it's not part of your question. I'm assuming this means you have the JSON well-handled and if we get these strings how you want them, you've got it from there.
var x = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine().Trim();
if (line.Contains("<FIPS>"))
{
x.Add(line.Replace(Environment.NewLine, " "));
}
else
{
var s = String.Concat(x.Last(), line.Replace(Environment.NewLine, string.Empty), " ");
x[x.Count - 1] = s;
}
}
Much of the point here is to separate the organization of the data away from actually putting it into your object. From here, you can iterate through the list in a foreach, creating new objects based on the results of string.Split() on each string in your List<string>.
I've been parsing text files for over 40 years. Code below is sample of what I've done
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Oppgave3Lesson1
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
WinterJsonModel data = new WinterJsonModel();
data.ParseFile(FILENAME);
}
}
public class WinterJsonModel
{
public static List<WinterJsonModel> samplData = new List<WinterJsonModel>();
public string fips { get; set; }
public string state { get; set; }
public string wfo { get; set; }
public List<Group> groups = new List<Group>();
public void ParseFile(string winterBoundsPath)
{
WinterJsonModel winterJsonModel = null;
Group group = null;
List<KeyValuePair<decimal, decimal>> values = null;
using (var reader = new StreamReader(winterBoundsPath))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine().Trim();
if (line.Length > 0)
{
if (line.StartsWith("<FIPS>"))
{
winterJsonModel = new WinterJsonModel();
WinterJsonModel.samplData.Add(winterJsonModel);
string[] rawData = line.Split(new char[] { '<', '>' }, StringSplitOptions.RemoveEmptyEntries);
winterJsonModel.fips = rawData[1];
winterJsonModel.state = rawData[3];
winterJsonModel.wfo = rawData[5];
group = null; // very inportant line
}
else
{
decimal[] rawData = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(x => decimal.Parse(x)).ToArray();
//if odd number of numbers in a line
if (rawData.Count() % 2 == 1)
{
group = new Group();
winterJsonModel.groups.Add(group);
group.id = (int)rawData[0];
//remove group number from raw data
rawData = rawData.Skip(1).ToArray();
}
for (int i = 0; i < rawData.Count(); i += 2)
{
group.values.Add(new KeyValuePair<decimal, decimal>(rawData[i], rawData[i + 1]));
}
}
}
}
}
}
}
public class Group
{
public int id { get; set; }
public List<KeyValuePair<decimal, decimal>> values = new List<KeyValuePair<decimal, decimal>>();
}
}

Reading delimited text file?

I am trying to read from a delimited text file, but everything is returned in in one row and one column.
My connections string is
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
Path.GetDirectoryName(#textBox1txtPath.Text) + ";" +
"Extended Properties=\"text;HDR=YES;IMEX=1;Format=Delimited(|)\"");
And my text file reads:
ItemNumber|ProductStatus|UPC
0000012|closed|2525
Please assist
Okay, so one option would be to take a different approach. Consider the following code:
// read the entire file and store each line
// as a new element in a string[]
var lines = File.ReadAllLines(pathToFile);
// we can skip the first line because it's
// just headings - if you need the headings
// just grab them off the 0 index
for (int i = 1; i < lines.Length; i++)
{
var vals = lines[i].Split('|');
// do something with the vals because
// they are now in a zero-based array
}
This gets rid of that monstrosity of a connection string, eliminates the overhead of an Odbc driver, and drastically increases the readability of the code.
i don't know exactly what do you need, but you can do this:
if you have string str with the whole text in it you can do
string[] lines = str.Split('\n');// split it to lines;
and then for each line you can do
string[] cells = line.Split('|');// split a line to cells
if we take it to the next level we can do:
public class line
{
public int ItemNumber { get; set; }
public string ProductStatus { get; set; }
public int UPC { get; set; }
public line(string currLine)
{
string[] cells = currLine.Split('|');
int item;
if(int.TryParse(cells[0], out item))
{
ItemNumber = item;
}
ProductStatus = cells[1];
int upc;
if (int.TryParse(cells[2], out upc))
{
UPC = upc;
}
}
}
and then:
string[] lines = str.Substring(str.IndexOf("\n")).Split('\n');// split it to lines;
List<line> tblLines = new List<line>();
foreach(string curr in lines)
{
tblLines.Add(new line(curr);
}
It's right in the framework -- TextFieldParser. Don't worry about the namespace, it was originally a shim for folks converting from VB6, but it's very useful. Here's a SSCCE that demonstrates its use for a number of different delimiters:
class Program
{
static void Main(string[] args)
{
var comma = #"one,""two, yo"",three";
var tab = "one\ttwo, yo\tthee";
var random = #"onelol""two, yo""lolthree";
var parser = CreateParser(comma, ",");
Console.WriteLine("Parsing " + comma);
Dump(parser);
Console.WriteLine();
parser = CreateParser(tab, "\t");
Console.WriteLine("Parsing " + tab);
Dump(parser);
Console.WriteLine();
parser = CreateParser(random, "lol");
Console.WriteLine("Parsing " + random);
Dump(parser);
Console.WriteLine();
Console.ReadLine();
}
private static TextFieldParser CreateParser(string value, params string[] delims)
{
var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(ToStream(value));
parser.Delimiters = delims;
return parser;
}
private static void Dump(TextFieldParser parser)
{
while (!parser.EndOfData)
foreach (var field in parser.ReadFields())
Console.WriteLine(field);
}
static Stream ToStream(string value)
{
return new MemoryStream(Encoding.Default.GetBytes(value));
}
}

Categories