Passing Data From Text File to Constructor - c#

I'm looking for a way to pass information from a text file into a constructor so that I can create an array of that constructor object with each object in the array holding information from the rows of the text file.
The constructor is formatted as follows:
public Member(string name, int number, decimal rate, double hours)
While the text file is formatted as such:
Eric Wallace, 352456, 15.88, 32.20
Clara Kell, 233424, 35.88, 18.76
Darren Price, 656795, 27.82, 20.25
etc...
and each Member will go into an array.
In the end, what I need is for each row to be split up and passed to the constructor in a way where each row becomes its own member in an array so that they can be output one after another in a loop or called individually as rows.

My approach would begin with making an interface that all my "buildable" data types will implement. I want my data models deciding how they are built from a string:
public interface IBuildableFromString
{
public IBuildableFromString Build(string str, string seperator = ",");
}
Then make Member implement it like so:
public class Member : IBuildableFromString
{
public string Name { get; set; }
public int Number { get; set; }
public decimal Rate { get; set; }
public double Hours { get; set; }
public Member() { }
public Member(string name, int number, decimal rate, double hours)
{
Name = name;
Number = number;
Rate = rate;
Hours = hours;
}
public IBuildableFromString Build(string str, string seperator = ",")
{
try
{
string[] parts = str.Split(seperator);
return new Member(parts[0], int.Parse(parts[1]),
decimal.Parse(parts[2]), double.Parse(parts[3]));
}
catch
{
return null;
}
}
}
Then the method to read the file and build the object data:
public static T[] BuildData<T>(string filePath) where T :
IBuildableFromString, new()
{
List<T> dataObjects = new List<T>();
string[] lines = File.ReadAllLines(filePath);
foreach (string line in lines)
{
if (!String.IsNullOrEmpty(line))
{
var newMember = new T().Build(line);
if (newMember != null)
dataObjects.Add((T)newMember);
}
}
return dataObjects.ToArray();
}
Lastly, call the function above like so:
static void Main(string[] args)
{
var data = BuildData<Member>(#"path_to_your_file.txt");
}
It probably needs more error checking, but this was the most extensible way I could think of doing it. Cheers!

As long as your file is well-formed, then this would work:
Member[] members =
File
.ReadLines(#"mytextfile.txt")
.Select(x => x.Split(',').Select(y => y.Trim()).ToArray())
.Select(x => new Member(x[0], int.Parse(x[1]), decimal.Parse(x[2]), double.Parse(x[3])))
.ToArray();

I will use StreamReader to read the txt file, then use replace to eliminate spaces, and then use split to split the data.
Use StreamReader to read text from a file:
StreamReader sr = new StreamReader(#"C:\demo\de.txt")
Make Member implement it like so:
public class Member {
public string Name { get; set; }
public int Number { get; set; }
public decimal Rate { get; set; }
public double Hours { get; set; }
public Member(string name, int number, decimal rate, double hours) {
Name = name;
Number = number;
Rate = rate;
Hours = hours;
}
}
Call the data like this:
foreach (var item in members) {
Console.WriteLine($"{ item.Name} { item.Number} { item.Rate} { item.Hours}");
}
Total code:
using System;
using System.Collections.Generic;
using System.IO;
namespace ConsoleApp2 {
class Program {
static void Main(string[] args) {
List<Member> members = new List<Member>();
try {
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(#"C:\demo\de.txt")) {
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null) {
line = line.Replace(" ", "");
string[] tmp = line.Split(',');
string name = tmp[0];
int number = Convert.ToInt32(tmp[1]);
decimal rate = Convert.ToDecimal(tmp[2]);
double hours = Convert.ToDouble(tmp[3]);
members.Add(new Member(name, number, rate, hours));
}
}
} catch (Exception e) {
// Let the user know what went wrong.
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
foreach (var item in members) {
Console.WriteLine($"{ item.Name} { item.Number} { item.Rate} { item.Hours}");
}
Console.ReadLine();
}
public class Member {
public string Name { get; set; }
public int Number { get; set; }
public decimal Rate { get; set; }
public double Hours { get; set; }
public Member(string name, int number, decimal rate, double hours) {
Name = name;
Number = number;
Rate = rate;
Hours = hours;
}
}
}
}
If you have questions, please add a comment.

Related

Reading CSV file - Object Oriented way

I'd like to parse a csv file in my course that I attend, The cvs file looks like this:
john; 3.5; 32111
etc
I've created a Class for that:
class Student
{
public string name { get; set; }
public double average { get; set; }
public int social_number { get; set; }
public Student(string name, double average, int social_number)
{
this.name = name;
this.average = average;
this.social_number = social_number;
}
public void CSV_digest(string csv_line)
{
if (csv_line != "")
{
string[] chunks = csv_line.Split(';');
name = chunks[0];
average = Convert.ToDouble(chunks[1]);
social_number = Convert.ToInt32(chunks[2]);
}
}
}
I don't really know how to propagate the Student type array:
class Program
{
static void Main(string[] args)
{
StreamReader csv = new StreamReader("students.csv", Encoding.UTF8);
string[] csv_lines = csv.ReadToEnd().Split('\n');
Student[] students = new Student[csv_lines.Length - 1];
for (int i = 0; i < csv_lines.Length; i++)
{
students[i] =
}
Console.ReadKey();
}
}
Could you please help me with this? I'd really like to utilize classes.
There is really no reason to use a library when the code to read CSV is very simple. See my code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string filename = #"c:\temp\test.csv";
static void Main(string[] args)
{
StreamReader csv = new StreamReader(filename);
string line = "";
List<Student> students = new List<Student>();
while((line = csv.ReadLine()) != null)
{
students.Add(new Student(line));
}
Console.ReadKey();
}
}
class Student
{
public string name { get; set; }
public double average { get; set; }
public int social_number { get; set; }
public Student(string csv_line)
{
if (csv_line != "")
{
string[] chunks = csv_line.Split(';');
name = chunks[0];
average = Convert.ToDouble(chunks[1]);
social_number = Convert.ToInt32(chunks[2]);
}
}
}
}

Loading data from 11 column CSV file into separate collections

First off i'm a bit of a novice at C#
So I have a CSV file with 11 columns and over 20,000 rows, its just a bunch of data from a sports tracking gps. What I want to do is be able to take that data from the CSV and load each column into a seperate collection, however I can't get it to work the way I want it.
I've spent ages searching up how to do this properly, but all i've managed to muster together this janky code that does load all the data into the collections, but will only let me load each piece of data into the collection as a string (not as decimal or char, which I need for some [yes I've tried delcaring the collections as decimal or char before]).
So what I need help with is being able to actually load the data from the CSV file into the collection as the data type I want, and if there's an easy way to skip the first 8 or so lines which are just headers.
The list of data types I require are as follows (in order of declared)
decimal
decimal
char
decimal
char
decimal
string
string
decimal
decimal
string
Here is the code i'm currently using:
//Seprate class for all the collection declarations
public static class GPSdata
{
public static List<string> time = new List<string>(); //time (in seconds, advances by 0.2)
public static List<string> lat = new List<string>(); //Latitude
public static List<string> NS = new List<string>(); //North/South
public static List<string> lon = new List<string>(); //Longtitude
public static List<string> EW = new List<string>(); //East/West
public static List<string> knots = new List<string>(); //Speed in Knots
public static List<string> date = new List<string>(); //Date [ddmmyy]
public static List<string> sats = new List<string>(); //**No clue**
public static List<string> HDOP = new List<string>(); //Satelite Horizontal error
public static List<string> alt = new List<string>(); //Elevation (above msl)
public static List<string> rawSV = new List<string>(); //Space Vehicle
}
//Method for loading the CSV data into the collections
public void LoadCSV(string filepath)
{
using (StreamReader reader = new StreamReader(filepath))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
GPSdata.time.Add(values[0]);
GPSdata.lat.Add(values[1]);
GPSdata.NS.Add(values[2]);
GPSdata.lon.Add(values[3]);
GPSdata.EW.Add(values[4]);
GPSdata.knots.Add(values[5]);
GPSdata.date.Add(values[6]);
GPSdata.sats.Add(values[7]);
GPSdata.HDOP.Add(values[8]);
GPSdata.rawSV.Add(values[9]);
GPSdata.alt.Add(values[10]);
}
}
}
Also heres an example of the data from the file i'm reading off:
31350.2,3750.9188,S,14458.8652,E,7.98,50817,0,2.3,0,23
31350.4,3750.9204,S,14458.867,E,6.66,50817,0,2.3,0,23
Sounds like you are asking two questions here, parsing text into other datatypes, which is discussed in the other answer. here another question that describes that in better detail. String Parsing in C#. The second part you are asking is about skipping header information in you csv files. Use the ReadLine() method on the StreamReader to skip some lines like so:
using (StreamReader reader = new StreamReader(filepath))
{
for(int i = 0; i<8; ++i){
reader.ReadLine();
}
while (!reader.EndOfStream)
{
// the stuff you are already doing
}
}
Separate collection for each property is not the proper approach.
This may be what you are looking for:
public class GPSdata
{
public TimeSpan time { get; set; } //time (in seconds, advances by 0.2)
public int latDegrees { get; set; } //Latitude
public int latMinutes { get; set; } //Latitude
public int latSeconds { get; set; } //Latitude
public string NS { get; set; } //North/South
public int lonDegrees { get; set; } //Longtitude
public int lonMinutes { get; set; } //Longtitude
public int lonSeconds { get; set; } //Longtitude
public string EW { get; set; } //East/West
public decimal knots { get; set; } //Speed in Knots
public DateTime date { get; set; } //Date [ddmmyy]
public int sats { get; set; } //**No clue**
public decimal HDOP { get; set; } //Satelite Horizontal error
public decimal alt { get; set; } //Elevation (above msl)
public int rawSV { get; set; } //Space Vehicle
}
public static List<GPSdata> LoadCSV(string filepath)
{
List<GPSdata> data = new List<GPSdata>();
using (StreamReader reader = new StreamReader(filepath))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
string[] values = line.Split(',');
GPSdata gpsdata = new GPSdata();
gpsdata.time = new TimeSpan((long)(decimal.Parse(values[0]) * (decimal)1.0E07));
int latDecimalPoint = values[1].IndexOf(".");
gpsdata.latSeconds = int.Parse(values[1].Substring(latDecimalPoint + 1));
gpsdata.latMinutes = int.Parse(values[1].Substring(latDecimalPoint - 2, 2));
gpsdata.latDegrees = int.Parse(values[1].Substring(0, latDecimalPoint - 2));
gpsdata.NS = values[2];
int lonDecimalPoint = values[3].IndexOf(".");
gpsdata.lonSeconds = int.Parse(values[3].Substring(lonDecimalPoint + 1));
gpsdata.lonMinutes = int.Parse(values[3].Substring(lonDecimalPoint - 2, 2));
gpsdata.lonDegrees = int.Parse(values[3].Substring(0, lonDecimalPoint - 2));
gpsdata.EW = values[4];
gpsdata.knots = decimal.Parse(values[5]);
int dateLen = values[6].Length;
gpsdata.date = new DateTime(int.Parse(values[6].Substring(dateLen - 2)), int.Parse(values[6].Substring(0, dateLen - 4)), int.Parse(values[6].Substring(dateLen - 4, 2)));
gpsdata.sats = int.Parse(values[7]);
gpsdata.HDOP = decimal.Parse(values[8]);
gpsdata.rawSV = int.Parse(values[9]);
gpsdata.alt = decimal.Parse(values[10]);
data.Add(gpsdata);
}
}
return data;
}
You class should look something like this. The E/W is positive or negative longitude and S/N is positive or negative latitude.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.csv";
static void Main(string[] args)
{
new GPSdata(FILENAME);
}
}
//Seprate class for all the collection declarations
public class GPSdata
{
public static List<GPSdata> data = new List<GPSdata>();
public TimeSpan time { get; set; } //time (in seconds, advances by 0.2)
public int latDegrees { get; set; } //Latitude
public int latMinutes { get; set; } //Latitude
public int latSeconds { get; set; } //Latitude
public string NS { get; set; } //North/South
public int lonDegrees { get; set; } //Longtitude
public int lonMinutes { get; set; } //Longtitude
public int lonSeconds { get; set; } //Longtitude
public string EW { get; set; } //East/West
public decimal knots { get; set; } //Speed in Knots
public DateTime date { get; set; } //Date [ddmmyy]
public int sats { get; set; } //**No clue**
public decimal HDOP { get; set; } //Satelite Horizontal error
public decimal alt { get; set; } //Elevation (above msl)
public int rawSV { get; set; } //Space Vehicle
public GPSdata() { }
public GPSdata(string filepath)
{
int lineNumber = 0;
StreamReader reader = new StreamReader(filepath);
string line = "";
while ((line = reader.ReadLine()) != null)
{
if (++lineNumber > 8)
{
try
{
string[] values = line.Split(',');
GPSdata gpsdata = new GPSdata();
GPSdata.data.Add(gpsdata);
gpsdata.time = new TimeSpan((long)(decimal.Parse(values[0]) * (decimal)1.0E07));
int latDecimalPoint = values[1].IndexOf(".");
gpsdata.latSeconds = int.Parse(values[1].Substring(latDecimalPoint + 1));
gpsdata.latMinutes = int.Parse(values[1].Substring(latDecimalPoint - 2, 2));
gpsdata.latDegrees = int.Parse(values[1].Substring(0, latDecimalPoint - 2));
gpsdata.NS = values[2];
int lonDecimalPoint = values[3].IndexOf(".");
gpsdata.lonSeconds = int.Parse(values[3].Substring(lonDecimalPoint + 1));
gpsdata.lonMinutes = int.Parse(values[3].Substring(lonDecimalPoint - 2, 2));
gpsdata.lonDegrees = int.Parse(values[3].Substring(0, lonDecimalPoint - 2));
gpsdata.EW = values[4];
gpsdata.knots = decimal.Parse(values[5]);
int dateLen = values[6].Length;
gpsdata.date = new DateTime(int.Parse(values[6].Substring(dateLen - 2)), int.Parse(values[6].Substring(0, dateLen - 4)), int.Parse(values[6].Substring(dateLen - 4, 2)));
gpsdata.sats = int.Parse(values[7]);
gpsdata.HDOP = decimal.Parse(values[8]);
gpsdata.rawSV = int.Parse(values[9]);
gpsdata.alt = decimal.Parse(values[10]);
}
catch (Exception ex)
{
Console.WriteLine("Error Line Number : '{0}', Text : '{1}'", lineNumber,line);
}
}
}
Console.ReadLine();
}
}
}

CsvHelper - Read different record types in same CSV

I'm trying to read two types of records out of a CSV file with the following structure:
PlaceName,Longitude,Latitude,Elevation
NameString,123.456,56.78,40
Date,Count
1/1/2012,1
2/1/2012,3
3/1/2012,10
4/2/2012,6
I know this question has been covered previously in
Reading multiple classes from single csv file using CsvHelper
Multiple Record Types in One File?
but when I run my implementation it gets a CsvMissingFieldException saying that Fields 'Date' do not exist in the CSV file. I have two definition and map classes, one for the location and the other for the counts, which are:
public class LocationDefinition
{
public string PlaceName { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public double Elevation { get; set; }
}
public sealed class LocationMap : CsvClassMap<LocationDefinition>
{
public LocationMap()
{
Map(m => m.PlaceName).Name("PlaceName");
Map(m => m.Longitude).Name("Longitude");
Map(m => m.Latitude).Name("Latitude");
Map(m => m.Elevation).Name("Elevation");
}
}
public class CountDefinition
{
public DateTime Date { get; set; }
public int Count { get; set; }
}
public sealed class CountMap : CsvClassMap<CountDefinition>
{
public CountMap()
{
Map(m => m.Date).Name("Date");
Map(m => m.Count).Name("Count");
}
}
The code that I have for reading the csv file is:
LocationDefinition Location;
var Counts = new List<CountDefinition>();
using (TextReader fileReader = File.OpenText(#"Path\To\CsvFile"))
using (var csvReader = new CsvReader(fileReader))
{
csvReader.Configuration.RegisterClassMap<LocationMap>();
csvReader.Configuration.RegisterClassMap<CountMap>();
// Only reads a single line of Location data
csvReader.Read();
LocationData = csvReader.GetRecord<LocationDefinition>();
csvReader.Read(); // skip blank line
csvReader.Read(); // skip second header section
// Read count data records
while (csvReader.Read())
{
var tempCount = csvReader.GetRecord<CountDefinition>();
Counts.Add(tempCount);
}
}
The exception gets thrown on the tempCount line. From what I can tell it still expects a Location record, but I would have thought GetRecord<CountDefinition> would specify the record type. I've also tried ClearRecordCache and unregistering the LocationMap to no avail.
How should this code be changed to get it to read a csv file of this structure?
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
enum State
{
FIND_RECORD,
GET_LOCATION,
GET_DATES
}
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(FILENAME);
State state = State.FIND_RECORD;
LocationDefinition location = null;
string inputLine = "";
while ((inputLine = reader.ReadLine()) != null)
{
inputLine = inputLine.Trim();
if (inputLine.Length == 0)
{
state = State.FIND_RECORD;
}
else
{
switch (state)
{
case State.FIND_RECORD :
if (inputLine.StartsWith("PlaceName"))
{
state = State.GET_LOCATION;
}
else
{
if (inputLine.StartsWith("Date"))
{
state = State.GET_DATES;
}
}
break;
case State.GET_DATES :
if (location.dates == null) location.dates = new CountDefinition();
location.dates.dates.Add(new CountDefinition(inputLine));
break;
case State.GET_LOCATION :
location = new LocationDefinition(inputLine);
break;
}
}
}
}
}
public class LocationDefinition
{
public static List<LocationDefinition> locations = new List<LocationDefinition>();
public CountDefinition dates { get; set; }
public string PlaceName { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public double Elevation { get; set; }
public LocationDefinition(string location)
{
string[] array = location.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
PlaceName = array[0];
Longitude = double.Parse(array[1]);
Latitude = double.Parse(array[2]);
Elevation = double.Parse(array[3]);
locations.Add(this);
}
}
public class CountDefinition
{
public List<CountDefinition> dates = new List<CountDefinition>();
public DateTime Date { get; set; }
public int Count { get; set; }
public CountDefinition() { ;}
public CountDefinition(string count)
{
string[] array = count.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
Date = DateTime.Parse(array[0]);
Count = int.Parse(array[1]);
dates.Add(this);
}
}
}
I got a response from Josh Close on the issue tracker:
CsvReader not recognising different registered class maps
Here is his answer to this question:
Since you don't have a single header, you'll need to ignore headers
and use indexes instead. This brings up an idea though. I could have
the ReadHeader method parse headers for a specific record type.
Here is an example that should work for you though.
void Main()
{
LocationDefinition Location;
var Counts = new List<CountDefinition>();
using (var stream = new MemoryStream())
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
using (var csvReader = new CsvReader(reader))
{
writer.WriteLine("PlaceName,Longitude,Latitude,Elevation");
writer.WriteLine("NameString,123.456,56.78,40");
writer.WriteLine();
writer.WriteLine("Date,Count");
writer.WriteLine("1/1/2012,1");
writer.WriteLine("2/1/2012,3");
writer.WriteLine("3/1/2012,10");
writer.WriteLine("4/2/2012,6");
writer.Flush();
stream.Position = 0;
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.RegisterClassMap<LocationMap>();
csvReader.Configuration.RegisterClassMap<CountMap>();
csvReader.Read(); // get header
csvReader.Read(); // get first record
var locationData = csvReader.GetRecord<LocationDefinition>();
csvReader.Read(); // skip blank line
csvReader.Read(); // skip second header section
// Read count data records
while (csvReader.Read())
{
var tempCount = csvReader.GetRecord<CountDefinition>();
Counts.Add(tempCount);
}
}
}
public class LocationDefinition
{
public string PlaceName { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public double Elevation { get; set; }
}
public sealed class LocationMap : CsvClassMap<LocationDefinition>
{
public LocationMap()
{
Map(m => m.PlaceName);
Map(m => m.Longitude);
Map(m => m.Latitude);
Map(m => m.Elevation);
}
}
public class CountDefinition
{
public DateTime Date { get; set; }
public int Count { get; set; }
}
public sealed class CountMap : CsvClassMap<CountDefinition>
{
public CountMap()
{
Map(m => m.Date);
Map(m => m.Count);
}
}

match value in one list with another and write value to other list

I have one list that is written to this class:
public class keyfrs
{
public keyfrs() { }
public long regID { get; set; }
public long ID { get; set; }
public string county { get; set; }
public string state { get; set; }
}
List<keyfrs> k = {1,2,3,4}] regID
{A,B,C,D} ID
I have another list class like this:
public class states
{
public states() { }
public long regID { get; set; }
public string state { get; set; }
public string county { get; set; }
}
List<states> s = {1,2,3,4}regID
{MA,NY,CT}state
{Suffolk,NY,Hampden}county
Want to write the county and state to the keyfrs list that matches with the regID from the lists.
What my program does so far is parse in two files and write each one to the different class list it corresponds to. As you can see both classes have a regID column. What I need to do is match the two lists together on regID and write the county and state to the keyfrs list class to then output that list to a new file with these added column in it.
static void Main(string[] args)
{
PARSEkeYfrs();
parsestateFile();
matchValues();
outputFile();
}
private static void outputFile()
{
string filename = #"c:\keyswCounty.csv";
using(StreamWriter write = new StreamWriter(filename))
{
write.WriteLine("RegIF"+","+"ID"+","+"County"+","+"State");
foreach(keyfrs k in keysandID)
{
write.WriteLine(k.regID +"," +k.ID+","+k.county+","+k.state);
}
}
}
private static void matchValues()
{
foreach(keyfrs k in keysandID)
{
}
}
private static void parsestateFile()
{
int a = 0;
string filename = #"c:\ALLStates.txt";
using (StreamReader read = new StreamReader(filename))
{
read.ReadLine();
while (!read.EndOfStream)
{
a++;
try{
string line = read.ReadLine();
string[] splitline = line.Split(',');
if(splitline[1]!="")
{
states s = new states();
s.regID = Convert.ToInt64(splitline[0]);
s.county = Convert.ToString(splitline[1]);
s.state = Convert.ToString(splitline[2]);
stateFile.Add(s);
}
}
catch(Exception ex)
{
string.Format("error:{0}" + ex.Message.ToString());
}
}
}
}
private static void PARSEkeYfrs()
{ int a = 0;
string filename = #"c:\key_frs.csv";
using (StreamReader read = new StreamReader(filename))
{
read.ReadLine();
while (!read.EndOfStream)
{
try{
a++;
string line = read.ReadLine();
string[] splitline = line.Split(',');
if(splitline[1]!="")
{
keyfrs k = new keyfrs();
k.regID = Convert.ToInt64(splitline[0]);
k.ID = Convert.ToInt64(splitline[1]);
k.county = "";
k.state = "";
keysandID.Add(k);
}
}
catch(Exception ex)
{
string.Format("error:{0}"+ex.Message.ToString());
}
}
}
}
switched the state list to a dictionary and matched the values by the key value pair by using the TryGetValue method.

ordering generic list by size property

Hi I have had to use interfaces before but ive been told i need to implement icomparable in this instance. see below:
internal class doorItem : IComparable
{
public int CompareTo(doorItem other)
{
// The temperature comparison depends on the comparison of the
// the underlying Double values. Because the CompareTo method is
// strongly typed, it is not necessary to test for the correct
// object type.
return GetNumber(productSize).CompareTo(GetNumber(other.productSize));
}
public string variations { get; set; }
public double pricerange { get; set; }
public string viewDetailsLink { get; set; }
public string height { get; set; }
public string width { get; set; }
public string productSize { get; set; }
public string productImage { get; set; }
public int countItemsOnSale { get; set; }
public string optionFor35Product { get; set; }
private int GetNumber(string str)
{
//this method gets the int out of the string
int length = str.Length;
string output = String.Empty;
int test = 0;
bool err = false;
for (int i = 0; i <= length; i++)
{
try
{
test = Convert.ToInt32(str.Substring(i, 1));
}
catch
{
err = true;
}
if (!err)
output += str.Substring(i, 1);
else
break;
}
return Convert.ToInt32(output);
}
}
above is the class i have created, door sizes are returned like this: 4dr, 5dr, 6dr etc.. then the getnumber method gets the int out of the string.
i have a generic list in of my custom class in the main method like this:
List<doorItem> d = new List<doorItem>();
i cant work out how to order this list by door size.... PLEASE HELP
It's easiest to do this using LINQ. Then you don't even need to implement IComparable.
var sortedList = doorList.OrderBy( d => d.GetNumber(d.productSize ).ToList();
And make GetNumber public inside the doorItem class.
I don't know if performance is important, but that method for getting the number is pretty horrible, exceptions should only be used in exceptional circumstances! Suggest something like this
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (Char.IsNumber(c))
{
sb.append(c);
}
}
return Convert.ToInt32(sb.ToString());
For sorting you can do what stecya has suggested, or you could convert this method to a property and sort directly.
public int Size
{
get
{
return GetNumber(this.productSize);
}
}
...
d.OrderBy(x=>x.Size);

Categories

Resources