Read CSV file to multiple integers - c#

It has been a few years since i have messed with C# or programming for that matter. I am attempting to read a CSV file to multiple integers. The CSV file is formatted as follows
box1,3
box2,6
box3,10
...
box160,1
So far for my code i have the below. The TextFieldParser i got off of another question. I am not sure if that is even what i need. I do not need to keep the information before the "," on the CSV file i just need the information after the "," to correspond with the correct int in my code. Any help or pointers would be much appreciated.
int box1;
int box2;
int box3;
...
int box160;
using (TextFieldParser parser = new TextFieldParser(#"C:\SprinklerTimer\DailySprinklerTimer.csv"))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
//Processing row
string[] fields = parser.ReadFields();
foreach (string field in fields)
{
//TODO: Process field
}
}
}

For starters manually making 160 box integers is very inefficient. Try using an array.
int[] box; // declare numbers as an int array of any size
box = new int[160]; //New box array for 0-159
and you can either do the same for the value, I.e. a value[] array or what I would is make box a struct instead of int, where the struct has two integers.
struct SimpleStruct
{
int name, value;
}
SimpleStruct[] box; // declare numbers as an int array of any size
box = new SimpleStruct[160]; //New box array for 0-159
And to go on to your actual question, I would recommend this question which will help if you implement my above changes.
Read CSV files to two arrays c#

Related

Reading/writing struct containing a variable-size 2D array using C#

I am rewriting some VB code in C# and am struggling a bit with a binary write/read operation. I have got a structure (equivalent to VB UDT) which contains a header and a variable-size 2D array. The row and column count is stored in the header.
Possibly I should be using an object rather than a struct, but I think that is a different discussion and unless it is a really bad idea I would prefer to stick with the struct for now.
I have done this sort of thing using VB many times and it is accomplished in a few lines of code. What I would generally do is something like this...
To write:
1) Dump UDT to a binary file with a Put statement.
To read:
1) Get the row and column counts from the file header using Get statements
2) Dim UDT and size the array part using the column/row counts found above
3) Read file contents into variable using a Get statement
My C# version is currently something like this:
using (BinaryReader b = new BinaryReader(File.Open( [filename] ,FileMode.Open)))
{
// Read number of rows and columns...
byte[] buff = b.ReadBytes(Marshal.SizeOf(typeof(GridStructHeader))); // read byte array
GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned); // protect buffer from GC
//Marshal the bytes...
GridStructHeader h =
(GridStructHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
typeof(GridStructHeader));
handle.Free(); // give control of the buffer back to the GC
// Create structure...
GridStruct grd = new GridStruct();
grd.Cell = new GridCell[h.NumCols, h.NumRows];
// Read grid into memory...
buff = b.ReadBytes(Marshal.SizeOf(grd)); // size buffer to match structure
handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
grd = (GridStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
typeof(GridStruct));
handle.Free();
}
GridStruct is a struct containing the header and 2D data array. The relevant part of it looks like this:
[Serializable]
struct GridStruct
{
public int NumCols;
public int NumRows;
public GridCell[,] Cell;
}
GridStructHeader is a data type used for convenience here, and contains only the first part of the header. I am using this as a way of reading the row and column count (both Int data type). I initially tried to do this using ReadInt32() to read the values individually, but this wasn't working and I put it down to Serialization.
GridStructHeader contains the row and column count (and some other fields, omitted here for simplicity)
[Serializable]
struct GridStructHeader
{
public int NumCols;
public int NumRows;
}
GridCell is a struct containing the contents of each cell in the grid (AKA matrix AKA 2D array).
When I run the above I am getting an AccessViolation exception at the line
grd = (GridStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(GridStruct));
My methodology is not quite right, I think. If anyone can advise how best to do this it would be appreciated. It doesn't have to be super-fast, particularly. Clarity and brevity of code are of higher priority.

how to convert a String list into a String array then converting it into an int array then counting the total sum of the numbers in the array?

So I am so fresh into the world of programming, starting new, I decided to start messing around in C# to create simple apps from ideas that come to mind, with this little app, I'm trying to have multiple TextBoxes named d1,d2,d3,d4,etc... the user inserts numbers into the textboxes then clicks button1, which begins the process in the code below creating a new list which contains all of the values of the textboxes and then the list is converted to an array and the array is then converted into an int array, etc....
BUT, when starting the application and I add values to the textboxes and then click button1, it shows 2 error like shows in the //gray code line below
Please help.
private void button1_Click(object sender, EventArgs e)
{
List<string> dodo = new List<string>();
dodo.Add(d1.Text); dodo.Add(d2.Text); dodo.Add(d3.Text); dodo.Add(d4.Text); dodo.Add(d5.Text);
dodo.Add(d6.Text); dodo.Add(d7.Text); dodo.Add(d8.Text); dodo.Add(d9.Text); dodo.Add(d10.Text);
dodo.Add(d11.Text); dodo.Add(d12.Text); dodo.Add(d13.Text); dodo.Add(d14.Text); dodo.Add(d15.Text);
dodo.Add(d16.Text); dodo.Add(d17.Text); dodo.Add(d18.Text); dodo.Add(d19.Text); dodo.Add(d20.Text);
foreach(string numb in dodo)
{
if (numb == "")
numb = "0"; //numb word has a red underline
}
string[] terms = dodo.ToArray();
int[] valv = {};
int x = 0;
for(int i=0;i<=19;i++)
{
valv[i] = int.Parse(terms[i]); //the ; in the end has a red underline and shows "FormatException was unhandled" error
i++;
x = x + valv[i];
}
string myString;
myString = x.ToString();
Result1.Text = myString;
}
you can't change the iteration variable which is numb in your case. Please change in the List container instead
List<string> dodo = new List<string>();
dodo.Add(d1.Text); dodo.Add(d2.Text); dodo.Add(d3.Text); dodo.Add(d4.Text); dodo.Add(d5.Text);
dodo.Add(d6.Text); dodo.Add(d7.Text); dodo.Add(d8.Text); dodo.Add(d9.Text); dodo.Add(d10.Text);
dodo.Add(d11.Text); dodo.Add(d12.Text); dodo.Add(d13.Text); dodo.Add(d14.Text); dodo.Add(d15.Text);
dodo.Add(d16.Text); dodo.Add(d17.Text); dodo.Add(d18.Text); dodo.Add(d19.Text); dodo.Add(d20.Text);
int k = 0;
foreach (string numb in dodo)
{
if (numb == "")
{
//numb = "0"; //numb word has a red underline
dodo[k] = "0";
}
k++;
}
Now your code on parsing into integer won't give any runtime error.
The first line "tells" you that you are not able to assign a new value to the variable which is used as a foreach iteration variable.
The second line, "tells" you that you have string value which is not able to be parsed correctly (e.g. user put string which is not a number). To avoid this you can use Int32.TryParse method instead, which will safely try to parse the given string.
The best and easiest way to achieve what you need is using LINQ methods, here is the example based on few things/assumptions:
Since you are converting empty strings into zeros, you could simply skip those entries from counting
To avoid FormatException, you should use TryParse method instead. Since TryParse method will safely parse the given string, you don't even have to filter empty strings at all (they will be skipped). However, I deliberately left filtering part, to get you a better overview of a solution.
You can use list initializer to make list initialization more readable
Solution:
List<string> dodo = new List<string>()
{
d1.Text, d2.Text //...others
};
int sum = dodo
.Where(item => !String.IsNullOrEmpty(item))
.Sum(item =>
{
if (Int32.TryParse(item, out int parsedItem))
{
return parsedItem;
}
return 0;
});
You can get more familiar with LINQ and used methods on following link

How to access individual fields within struct array

I'm trying to complete an assignment and I'm having trouble with the following (I have worked on this for the last 12 hours). Please help.
I have opened a file, saved the file into an struct array. Can access each element of the struct but don't know how I can access each individual field. i.e
Struct
//struct to hold the hand values
public struct CurrentHand
{
public char cardSuit;
public int cardValue;
}
I need to extract the cardValue into an array or variables so I can evaluate each record i.e. is the hand a pair or two pair etc. I have no idea how to do this. From what I have found its not possible to access each field, is this true?
//Open file and load data into array
public static void LoadHandData(CurrentHand[] handData, string fileName)
{
string input = ""; //temporary variable to hold one line of data
string[] cardData; //temporary array to hold data split from input
//Open the file and read the contents
StreamReader readHand = new StreamReader(fileName);
input = readHand.ReadLine(); //one record
cardData = input.Split(' '); //split record into fields
for (int counter = 0; counter < handData.Length; counter++)
{
handData[counter].cardSuit = Convert.ToChar(cardData[counter *2]);
handData[counter].cardValue = Convert.ToInt16(cardData[counter *2 +1]);
}
readHand.Close();
}
To obtain an array containing the values of the cards you hold in your hand, you can do:
var values = handData.Select(x=>x.cardValue).ToArray();
var seeds = handData.Select(x=>x.cardSuit).ToArray();
By the way, your struct should be called Card or something like that, since an Hand is supposed to be a collection of cards. The name you gave to it is just confusing and makes your code less readeable.
Your problem is not clear to me. anyway you can access invidual fields using .
try this...
CurrentHand.cardValue
using above you can get and set value for CurrentHand structure.

Trouble with CSV formatting

Having problems with formatting CSV created from C# code. In the notepad file the output scrolls vertically down one row (the values seen in the structs below are output in one row. There is a row of numbers as well that appears directly below the struct values but the numbers should be in a new row beside the structs). When I open in excel it's a similar story only the output from the structs is where it should be however the row of numbers appears directly below the struct values but one row to the right if that makes sense, and the numbers should appear directly beside their corresponding struct values. The code I'm using is below.
Here are the structs for the dictionaries im working with.
public enum Genders
{
Male,
Female,
Other,
UnknownorDeclined,
}
public enum Ages
{
Upto15Years,
Between16to17Years,
Between18to24Years,
Between25to34Years,
Between35to44Years,
Between45to54Years,
Between55to64Years,
Between65to74Years,
Between75to84Years,
EightyFiveandOver,
UnavailableorDeclined,
}
the csv file that does the outputting using a streamwriter and stringbuilder.
public void CSVProfileCreate<T>(Dictionary<T, string> columns, Dictionary<T, int> data)
{
StreamWriter write = new StreamWriter("c:/temp/testoutputprofile.csv");
StringBuilder output = new StringBuilder();
foreach (var pair in columns)
{
//output.Append(pair.Key);
//output.Append(",");
output.Append(pair.Value);
output.Append(",");
output.Append(Environment.NewLine);
}
foreach (var d in data)
{
//output.Append(pair.Key);
output.Append(",");
output.Append(d.Value);
output.Append(Environment.NewLine);
}
write.Write(output);
write.Dispose();
}
And finally the method to feed the dictionaries into the csv creator.
public void RunReport()
{
CSVProfileCreate(genderKeys, genderValues);
CSVProfileCreate(ageKeys, ageValues);
}
Any ideas?
UPDATE
I fixed it by doing this:
public void CSVProfileCreate<T>(Dictionary<T, string> columns, Dictionary<T, int> data)
{
StreamWriter write = new StreamWriter("c:/temp/testoutputprofile.csv");
StringBuilder output = new StringBuilder();
IEnumerable<string> col = columns.Values.AsEnumerable();
IEnumerable<int> dat = data.Values.AsEnumerable();
for (int i = 0; i < col.Count(); i++)
{
output.Append(col.ElementAt(i));
output.Append(",");
output.Append(dat.ElementAt(i));
output.Append(",");
output.Append(Environment.NewLine);
}
write.Write(output);
write.Dispose();
}
}
You write Environment.NewLine after every single value that you output.
Rather than having two loops, you should have just one loop that outputs
A "pair"
A value
Environment.NewLine
for each iteration.
Assuming columns and data have the same keys, that could look something like
foreach (T key in columns.Keys)
{
pair = columns[key];
d = data[key];
output.Append(pair.Value);
output.Append(",");
output.Append(d.Value);
output.Append(Environment.NewLine);
}
Note two complications:
If pair.Value or d.Value contains a comma, you need to surround the output of that cell with double quotes.
If If pair.Value or d.Value contains a comma and also contains a double-quote, you have to double up the double-quote to escape it.
Examples:
Smith, Jr
would have to be output
"Smith, Jr"
and
"Smitty" Smith, Jr
would have to be output
"""Smitty"" Smith, Jr"
UPDATE
Based on your comment about the keys...
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
If you cannot use the key to associate the right pair with the right data, how do you make that association?
If you are iterating the dictionary and they happen to be in the order you hope, that is truly undefined behavior that could change with the next .NET service pack.
You need something reliable to relate the pair with the correct data.
About the var keyword
var is not a type, but rather a shortcut that frees you from writing out the entire type. You can use var if you wish, but the actual type is KeyValuePair<T, string> and KeyValuePair<T, int> respectively. You can see that if you write var and hover over that keyword with your mouse in Visual Studio.
About disposing resources
Your line
write.Dispose();
is risky. If any of your code throws an Exception prior to reaching that line, it will never run and write will not be disposed. It is strongly preferable to make use of the using keyword like this:
using (StreamWriter write = new StreamWriter("c:/temp/testoutputprofile.csv"))
{
// Your code here
}
When the scope of using ends (after the associated }), write.Dispose() will be automatically called whether or not an Exception was thrown. This is the same as, but shorter than,
try
{
StreamWriter write = new StreamWriter("c:/temp/testoutputprofile.csv");
// Your code here
}
finally
{
write.Dispose();
}

Naming a variable from a text file

I'm making a program in C# that uses mathematical sets of numbers. I've defined the class Conjunto (which means "set" in spanish). Conjunto has an ArrayList that contains all the numbers of the set. It also has a string called "ID" which is pretty much what it sounds; the name of an instance of Conjunto.
The program have methods that applies the operations of union, intersection, etc, between the sets.
Everything was fine, but now i've a text file with sentences like:
A={1,2,3}
B={2,4,5}
A intersection B
B union A
And so on. The thing is, i don't know how many sets the text file contains, and i don't know how to name the variables after those sentences. For example, name an instance of Conjunto A, and name another instance B.
Sorry for the grammar, english is not my native language.
Thanks!
It's pretty complicated to create varaibles dynamically, and pretty useless unless you have some already existing code that expects certain variables.
Use a Dictionary<string, Conjunto> to hold your instances of the class. That way you can access them by name.
First off, If you don't target lower version than .Net 2.0 use List instead of ArrayList. If I were you I wouldn't reinvent the wheel. Use HashSet or SortedSet to store the numbers and then you can use defined union and intersection.
Secondly, what is your goal? Do want to have just the output set after all operations? Do you want to read and store all actions and them process it on some event?
First of all, your program is taken from bad side. I would advice to start making new one. One of ways to name "variables" dynamicaly is by making class objects and editing their properties.
This is what I made as a starting platform:
First af all I have crated a class called set
class set
{
public string ID { get; set; }
public List<int> numbers { get; set; }
}
Then I have made the code to sort whole textfile into list of those classes:
List<set> Sets = new List<set>();
string textfile = "your text file";
char[] spliter = new char[] { ',' }; //switch that , to whatever you want but this will split whole textfile into fragments of sets
List<string> files = textfile.Split(spliter).ToList<string>();
int i = 1;
foreach (string file in files)
{
set set = new set();
set.ID = i.ToString();
char[] secondspliter = new char[] { ',' }; //switch that , to whatever you want but this will split one set into lone numbers
List<string> data = textfile.Split(secondspliter).ToList<string>();
foreach (string number in data)
{
bool success = Int32.TryParse(number, out int outcome);
if (success)
{
set.numbers.Add(outcome);
}
}
i++;
Sets.Add(set);
}
Hope it helps someone.

Categories

Resources