I want to add all properties values assigned during instantiation of Course class into text File.
CourseManager courseMng = new CourseManager();
Course prog1 = new Course();
Console.WriteLine(prog1.GetInfo());
Console.WriteLine();
prog1.CourseCode = "COMP100";
prog1.Name = "Programming 1";
prog1.Description = "Programming1 description";
prog1.NoOfEvaluations = 3;
Console.WriteLine(prog1.GetInfo());
Course prog2 = new Course("COMP123", "Programming2") { Description = "prog 2 desc", NoOfEvaluations = 2 };
Console.WriteLine(prog2.GetInfo());
courseMng.AddCourse(prog1);
courseMng.AddCourse(prog2);
This was my main and this is my CourseManager class
Course[] courses;
int numberOfCourses;
public int NumberOfCourses
{
get { return numberOfCourses; }
set { numberOfCourses = value; }
}
public Course[] Courses
{
get
{
return courses;
}
set
{
courses = value;
}
}
public CourseManager()
{
Courses = new Course[100];
}
public void AddCourse(Course aCourse)
{
Courses[numberOfCourses] = aCourse;
numberOfCourses++;
aCourse.Manager = this;
}
public void ExportCourses(string fileName, char Delim)
{
FileStream stream = null;
StreamWriter writer;
try
{
stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
writer = new StreamWriter(stream);
Course aCourse = new Course();
for(int i =0; i<numberOfCourses;i++)
{
//writer.WriteLine(courses.ToString());
writer.WriteLine("{0}{1}{2}{1}{3}{1}{4}", aCourse.CourseCode, Delim, aCourse.Name, aCourse.Description, aCourse.NoOfEvaluations);
}
writer.Close();
}
finally
{
stream.Close();
}
}
So the problem is when i try to writeline it just prints empty values. I want CourseCode,Name,Descrpition and NumberOfEvaluations to be written in .txt file.
If u need any other code please let me know
Thanks in advance
Your issue is where you are getting your data from in the lines
Course aCourse = new Course();
for(int i =0; i<numberOfCourses;i++)
{
//writer.WriteLine(courses.ToString());
writer.WriteLine("{0}{1}{2}{1}{3}{1}{4}", aCourse.CourseCode, Delim, aCourse.Name, aCourse.Description, aCourse.NoOfEvaluations);
}
The issue is you are writing out the values of the properties of aCourse which is never set to anything than a new Course() (as per the first line).
Try changing it to this
for(int i =0; i<numberOfCourses;i++)
{
Course aCourse = Courses[i];
//writer.WriteLine(courses.ToString());
writer.WriteLine("{0}{1}{2}{1}{3}{1}{4}", aCourse.CourseCode, Delim, aCourse.Name, aCourse.Description, aCourse.NoOfEvaluations);
}
In the second example we are setting the value of aCourse to be the next course in the iterator.
As per your comment
i have a file with different courses and i want to add it to courses
array. I am doing this
Course C = new Course();
C.CourseCode = reader.ReadLine();
C.Name = reader.ReadLine();
C.Description = reader.ReadLine();
C.NoOfEvaluations = Int32.Parse(reader.ReadLine());
courses[index++] = C;
But i am getting invalid input error at NoofEvaluations any solution?
The issue here is you exported the data in a single line via the writer.WriteLine method delimiting the values by a delimeter | or more exactly by the 'char Delim` paramter. In this case you need to read a single line into an array that is split by the same character. Somthing like.
var line = reader.ReadLine();
var array = line.Split('|'); // or char Delim if you prefer
var c = new Course();
c.CourseCode = array[0];
c.Name = array[1];
c.Description = array[2];
c.NoOfEvaluations = int.Parse(array[3]);
courses[index++] = c;
Instead of fixing your problem, I'm going suggest different code to clean things up. I would simplify as follows:
public class Course
{
public string CourseCode { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int NoOfEvaluations { get; set; }
public IEnumerable<Course> Courses { get; set; }
public Course()
{
Courses = new List<Course>();
}
//this will format the text to your specification
public string ToDelimitedString(char Delimiter)
{
return String.Format("{0}{4}{1}{4}{2}{4}{3}{5}"
, this.CourseCode
, this.Name
, this.Description
, this.NoOfEvaluations.ToString()
, Delimiter
, Environment.NewLine);
}
public void Export(string FileName, char Delimiter)
{
//this will be more efficient than writing on line at a time
var coursesExport = new StringBuilder();
foreach(var course in this.Courses)
{
coursesExport.Append(course.ToDelimitedString(Delimiter));
}
File.WriteAllText(FileName, coursesExport.ToString());
}
}
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.
passing a string like this to the code behind:
0,-1|1,-1|2,-1|3,-1|4,-1|5,-1|6,-1|7,-1|8,-1
I need to be able to asign the values before and after the "," symbol per each "|" symbol that exits in the string, into separated variables, "line" for first value (before the ",") and "group" for the next one (after the ",").
Right now I'm trying with this, but I'm having some issues with converting from string[] to string.
public static string GuardarGrupos(string parametro){
var data = parametro.Split(Convert.ToChar("|"));
var datos = "";
string[] linea;
var grupo = "";
//Iterate through each of the letters
foreach (var check in data)
{
datos = data[0];
linea = data[0].Split(Convert.ToChar(","));
}
return linea;
}
Any Idea how can I achieve this?
Make a class or struct to hold your values:
public class DataObject
{
public string X {get; set;}
public string Y {get; set;}
}
Return a List<T> of type DataObject
public static List<DataObject> GuardarGrupos(string parametro){
//List to return
List<DataObject> returnList = new List<DataObject>();
//Split the string on pipe to get each set of values
var data = parametro.Split('|'); //No need to do a convert.char(),
//String.Split has an overload that takes a character, use single quotes for character
//Iterate through each of the letters
foreach (var check in data)
{
//Split on comma to get the individual values
string[] values = check.Split(',');
DataObject do = new DataObject()
{
X = values[0];
Y = values[1];
};
returnList.Add(do);
}
return returnList;
}
Once you have the List<DataObject>, you can form line and group using linq and string.Join:
List<DataObject> myList = GuardarGrupos("0,-1|1,-1|2,-1|3,-1|4,-1|5,-1|6,-1|7,-1|8,-1");
string line = string.Join(",", myList.Select(x => x.X);
string group = string.Join(",", myList.Select(y => y.Y);
Instead of using local variables , create a Class that stores your retrieved values. then in the main you could handle/manipulate those values as required.
public class MyData
{
public string Datos { get; set; }
public string Linea { get; set; }
public string Grupo { get; set; }
}
public static List<MyData> myFunction(string parametro)
{
List<MyData> result = new List<MyData>();
var data = parametro.Split(Convert.ToChar("|"));
foreach (var check in data)
{
MyData temp = new MyData();
var line = check.Split(',');
temp.Datos = line[0];
temp.Linea = line[1];
temp.Grupo = check;
result.Add(temp);
}
return result;
}
static void Main(string[] args)
{
var t = myFunction("0,-1|1,-1|2,-1|3,-1|4,-1|5,-1|6,-1|7,-1|8,-1");
}
Here is a robust solution that's just a simple iteration over a string.
void Main()
{
var xs = "0,-1|1,-1|2,-1|3,-1|4,-1|5,-1|6,-1|7,-1|8,-1";
var stack = new Stack<Pair>();
stack.Push(new Pair());
foreach(var x in xs)
if(x == '|')
stack.Push(new UserQuery.Pair());
else
stack.Peek().Accept(x);
foreach (var x in stack.Reverse())
Console.WriteLine(x);
}
sealed class Pair
{
Action<char> _Accept;
readonly List<char> Line = new List<char>();
readonly List<char> Group = new List<char>();
public Pair()
{
_Accept = x => Line.Add(x);
}
public void Accept(char c)
{
if(c == ',')
_Accept = x => Group.Add(x);
else
_Accept(c);
}
public override string ToString()
{
return "Line:" + new string(Line.ToArray()) + " Group:" + new string(Group.ToArray());
}
}
My problem is that I have a list that contains a few strings and inside this list another list of decimals, something like this:
public class excelInventario
{
public excelInventario() { cols = new List<decimal>); }
public string codigo { get; set; }
public string nombre { get; set;} .
public List<decimal> cols { get; set; } //Lista de columnas
public decimal suma { get; set; }
public decimal stock { get; set; }
public decimal diferencia { get; set; }
public decimal precio { get; set; }
}
and now I need to put this in Excel. The problem is that when I use the method LoadFromCollection(MyList) the strings appear well in Excel, but the list of decimals is not put correctly, but:
System.Collections.Generic.List`1[System.Decimal].
Can I adapt this method or do I need to use a loop and put "manually" the row values one by one?
I suspect this second option it will be inefficient.
---------------EDIT TO ADD MORE CODE--------------
int tamcolumnas=excelin[0].cols.Count;
using (ExcelPackage package = new ExcelPackage(file))
{
ExcelWorksheet hoja = package.Workbook.Worksheets.Add("Comparativo unidades contadas VS stock");
hoja.Cells["A1"].Value = "CODART";
hoja.Cells["B1"].Value = "NOMBRE";
for(int i=0;i<tamcolumnas;i++)
{ hoja.Cells[1, i+3].Value = "COL"+(i+1); }
var MyList = new List<excelInventario>();
hoja.Cells.LoadFromCollection(MyList,true);
hoja.Cells[2, 3].LoadFromArrays(MyList.Select((r) => r.cols.Cast<object>).ToArray()));
in this last line is where fails.
Say:
System.ArgumentOutOfRangeException
The specified argument is outside the range of valid values.
Since those are Lists the closest you can get to automation is the LoadFromArray since those are not true objects. Its not exactly pretty since it requires casting so check for performance hits. Otherwise, it may be best to use plain old loops. Here is what I mean:
[TestMethod]
public void ListOfList_Test()
{
//http://stackoverflow.com/questions/33825995/how-to-use-loadfromcollection-in-epplus-with-a-list-containing-another-list-insi
//Throw in some data
var MyList = new List<TestExtensions.excelInventario>();
for (var i = 0; i < 10; i++)
{
var row = new TestExtensions.excelInventario
{
codigo = Path.GetRandomFileName(),
nombre = i.ToString(),
cols = new List<decimal> {i, (decimal) (i*1.5), (decimal) (i*2.5)}
};
MyList.Add(row);
}
//Create a test file
var fi = new FileInfo(#"c:\temp\ListOfList.xlsx");
if (fi.Exists)
fi.Delete();
int tamcolumnas = 10; // excelin[0].cols.Count;
using (ExcelPackage package = new ExcelPackage(fi))
{
ExcelWorksheet hoja = package.Workbook.Worksheets.Add("Comparativo unidades contadas VS stock");
hoja.Cells["A1"].Value = "CODART";
hoja.Cells["B1"].Value = "NOMBRE";
for (int i = 0; i < tamcolumnas; i++)
{
hoja.Cells[1, i + 3].Value = "COL" + (i + 1);
}
//var MyList = new List<TestExtensions.excelInventario>();
hoja.Cells.LoadFromCollection(MyList, true);
//hoja.Cells[2, 3].LoadFromArrays(MyList.Select((r) => r.cols.Cast<object>).ToArray()));
hoja.Cells[2, 3].LoadFromArrays(MyList.Select((r) => r.cols.Cast<object>().ToArray()));
package.Save();
}
}
I'm working on a homework problem for my computer science class. A cities census data is on a text file holding records for its citizens. Each line will have four fields(age, gender, marital status, and district) of different data types separated by a comma. For example, 22, F, M, 1.
How should I approach this? My thoughts are that I should use two 1D arrays, one for age and one for district. I need to be able to later count how many people are in each district, and how many people are in different age groups for the whole city.
How do I read each line and get the info I want into each array?
edit**
This is what I've managed to do so far. I'm trying to separate my data from fields into four different arrays. This is where I'm stuck.
FileStream fStream = new FileStream("test.txt", FileMode.Open, FileAccess.Read);
StreamReader inFile = new StreamReader(fStream);
string inputRecord = "";
string[] fields;
int[] ageData = new int[1000];
string[] genderData = new string[1000];
string[] maritalData = new string[1000];
int[] districtData = new int[1000];
inputRecord = inFile.ReadLine();
while (inputRecord != null)
{
fields = inputRecord.Split(',');
int i = 0;
ageData[i] = int.Parse(fields[0]);
genderData[i] = fields[1];
maritalData[i] = fields[2];
districtData[i] = int.Parse(fields[3]);
i++;
inputRecord = inFile.ReadLine();
}
edit 2**
First question, I've decided to use the below code to find out how many citizens are in each district of the census data.
for (int x = 1; x <= 22; x++)
for (int y = 0; y < districtData.Length; y++)
if (districtData[y] == x)
countDist[x]++;
for (int x = 1; x <= 22; x++)
Console.WriteLine("District " + x + " has " + countDist[x] + " citizens");
In my .Writeline when x reaches two digits it throws off my columns. How could I line up my columns better?
Second question, I am not quite sure how to go about separating the values I have in ageData into age groups using an if statement.
It sounds like each of the four fields have something in common... they represent a person surveyed by the census. That's a good time to use a class along the lines of
public class Person
{
public int Age { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public int District { get; set; }
}
Then, just read in all of the lines from the text file (if it's small, it's fine to use File.ReadAllLines()), and then create an instance of Person for each line in the file.
You can create a
List<Person> people;
to hold the Person instances that you parse from the text file.
Since the lines appear to be separated by commas, have a look at String.Split().
UPDATE
The attempt in your edit is pretty close. You keep creating a new i and initializing it to 0. Instead, initialize it outside your loop:
int i = 0;
while (inputRecord != null)
{
fields = inputRecord.Split(',');
Also you may want to trim excess spaces of of your input. If the fields are separated with ", " rather than just "," you will have excess spaces in your fields.
genderData[i] = fields[1].Trim();
maritalData[i] = fields[2].Trim();
How about this?
List<string[]> o = File.ReadAllLines(#"C:\TestCases\test.txt").Select(x => x.Split(',')).OrderBy(y => y[0]).ToList();
Each person is a string array in the list.
Each property is a index in the array eg: age is first.
The above code reads all lines comma delimits them orders them by age and adds them to the list.
public static class PersonsManager
{
public static PersonStatistics LoadFromFile(string filePath)
{
var statistics = new PersonStatistics();
using (var reader = new StreamReader(filePath))
{
var separators = new[] { ',' };
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line))
continue; //--malformed line
var lParts = line.Split(separators, StringSplitOptions.RemoveEmptyEntries);
if (lParts.Length != 4)
continue; //--malformed line
var person = new Person
{
Age = int.Parse(lParts[0].Trim()),
Gender = lParts[1].Trim(),
MaritalStatus = lParts[2].Trim(),
District = int.Parse(lParts[3].Trim())
};
statistics.Persons.Add(person);
}
}
return statistics;
}
}
public class PersonStatistics
{
public List<Person> Persons { get; private set; }
public PersonStatistics()
{
Persons = new List<Person>();
}
public IEnumerable<Person> GetAllByGender(string gender)
{
return GetByPredicate(p => string.Equals(p.Gender, gender, StringComparison.InvariantCultureIgnoreCase));
}
//--NOTE: add defined queries as many as you need
public IEnumerable<Person> GetByPredicate(Predicate<Person> predicate)
{
return Persons.Where(p => predicate(p)).ToArray();
}
}
public class Person
{
public int Age { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public int District { get; set; }
}
Usage:
var statistics = PersonsManager.LoadFromFile(#"d:\persons.txt");
var females = statistics.GetAllByGender("F");
foreach (var p in females)
{
Console.WriteLine("{0} {1} {2} {3}", p.Age, p.Gender, p.MaritalStatus, p.District);
}
I hope it helps.
I have spent hours trying to figure out why my database cannot find the table I have found numerous examples and none have seemed to help. I have created a separate class to handle the database operations so I can use it on multiple pages.
Here is the code
[Table]
public class MatchItem
{
[Column(IsPrimaryKey = true, CanBeNull=false,IsDbGenerated=true)]
public int MatchID { get; set; }
[Column(CanBeNull = false)]
public string MatchNumber { get; set; }
[Column(CanBeNull = false)]
public string EventName { get; set; }
[Column(CanBeNull = false)]
public DateTime Time { get; set; }
[Column(CanBeNull = false)]
public string[] RedTeams { get; set; }
[Column(CanBeNull = false)]
public string[] BlueTeams { get; set; }
[Column(CanBeNull = false)]
public int RedFinal { get; set; }
[Column(CanBeNull = false)]
public int BlueFinal{ get; set; }
}
Here is the Data context
public class MatchDataContext:DataContext
{
public MatchDataContext(string connectionString) :
base(connectionString)
{
}
public Table<MatchItem> Matches
{
get
{
return this.GetTable<MatchItem>();
}
}
}
I made a class so I could use it on multiple pages
public class MatchDBManager
{
private static string connectionString = #"Data Source=isostore:/DB.sdf";
public MatchDBManager()
{
initialize();
}
public void initialize()
{
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
if (Mchdb.DatabaseExists())
{
Console.WriteLine("DB already exists");
}
else
{
Mchdb.CreateDatabase();
Console.WriteLine("DB created");
}
}
}
public void addMatchData(IList<MatchItem> data)
{
//this.clearData();
//initialize();
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
Mchdb.Matches.InsertAllOnSubmit(data);
Mchdb.SubmitChanges();
}
}
public IList<MatchItem> getTeamData(string teamNum)
{
IList<MatchItem> MatchList = null;
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
IQueryable<MatchItem> mchQuery = from mch in Mchdb.Matches where (mch.RedTeams[0] == teamNum || mch.RedTeams[1] == teamNum || mch.RedTeams[2] == teamNum || mch.BlueTeams[0] == teamNum || mch.BlueTeams[1] == teamNum || mch.BlueTeams[2] == teamNum) select mch;
MatchList = mchQuery.ToList();
}
return MatchList;
}
public IList<MatchItem> getEventData(string eventID)
{
IList<MatchItem> MatchList = null;
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
IQueryable<MatchItem> mchQuery = from mch in Mchdb.Matches where mch.Event == eventID select mch;
MatchList = mchQuery.ToList();
}
return MatchList;
}
private void clearData()
{
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
if (Mchdb.DatabaseExists())
{
Mchdb.DeleteDatabase();
}
}
}
}
I have the error The specified table does not exist[Match].
Added here is where I download
public IList<MatchItem> ParseXML(XmlReader reader)
{
//List<string> save = new List<string>();
List<MatchItem> MatchList= new List<MatchItem>();
XElement matchData;
matchData = XElement.Load(reader);
StringBuilder output = new StringBuilder();
int count = 0;
var matches = from item
in matchData.Elements("match")
select item;
foreach (XElement eachmatch in matches)
{
MatchItem mch = new MatchItem();
string Time = ((eachmatch.Element("pubdate").Value).ToString());
mch.EventName = ((eachmatch.Element("event").Value).ToString());
mch.MatchNumber = ((eachmatch.Element("mch").Value).ToString() + (eachmatch.Element("typ").Value).ToString());
string[] RT = { eachmatch.Element("red1").Value.ToString(), eachmatch.Element("red2").Value.ToString(), eachmatch.Element("red3").Value.ToString() };
string[] BT = { eachmatch.Element("blue1").Value.ToString(), eachmatch.Element("blue2").Value.ToString(), eachmatch.Element("blue3").Value.ToString() };
string RF = ((eachmatch.Element("rfin").Value).ToString());
string BF = ((eachmatch.Element("bfin").Value).ToString());
// Time = Time.Substring(0, (Time.IndexOf("+") - 1));
mch.Time = DateTime.Parse(Time);
mch.RedTeams = RT;
mch.BlueTeams = BT;
mch.RedFinal = int.Parse(RF);
mch.BlueFinal= int.Parse(BF);
mch.MatchID = count;
count += 1;
MatchList.Add(mch);
}
return MatchList;
}
This is where I call this method
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
initializeDB();
if (e.Error == null)
{
XmlReader reader = XmlReader.Create(new StringReader(e.Result));
DownloadInfo di = new DownloadInfo();
IList <MatchItem>data= di.ParseXML(reader);
outputer(data);
addData(data.ToList<MatchItem>());
}
else
{
IList<MatchItem> data = getTeamData(strMyTeam);
outputer(data);
}
}
I ended up removing the DatabaseManager class and putting the functions in the main code
Then I output them to the screen here
public void outputer(IList<MatchItem> mch)
{
for (int i = 0; i < mch.Count; i++)
{
Score sc = new Score();
sc.Width = lsbData.Width;
sc.Height = sc.Height;
sc.Time = mch[i].Time.ToString();
sc.Event = mch[i].EventName;
sc.RT = mch[i].RedTeams[0] + " " + mch[i].RedTeams[1] + " " + mch[i].RedTeams[2];
sc.BT = mch[i].BlueTeams[0] + " " + mch[i].BlueTeams[1] + " " + mch[i].BlueTeams[2];
sc.RF = mch[i].RedFinal.ToString();
sc.BF = mch[i].BlueFinal.ToString();
lsbData.Items.Add(sc);
}
}
*note:score is a custom control that works(and worked) before the database code *
I don't see where you actually create a Match Object.
if you have you need to include that code in the question as well. and if you haven't, that would explain why it doesn't exist.
Addition
in order to add Match Objects to a list you will have to create the objects first then add them to the list, I don't think you can create the whole list of objects before creating each individual object.
more Additional Information
the object still needs to be created before you can add items to it. that is what the error is telling you. you don't have the object to insert data into.
Match Table1 = new Match();
this creates a new Match object which allows you to access the pieces of the object and insert data into the object like this
Table1.MatchNumber = 42
you can't add to something to a memory location until you set aside that memory location for that specific person and give it a name.
when you create that class you can add functions and all sorts of fun stuff to it, but you can't use any of it until you have created a Match Object.
you can't add something to a list that doesn't exist, you have to create the Match Object first, then add it to the list