Read values from file into multidimensionnal array - c#

I want to read files from an external datafile, stick them into an array to import to Unity3D.
So I started this:
int [,] positionTab = new int[noLoc,3];
StreamReader sr = new StreamReader(myTextFile);
while((line = sr.ReadLine()) != null)//read line by line up to the end
{
if (line.Contains("confTrain1"))
{
locationTrain1 = RetrieveValueInDataFile.locationTrain(line);
}
else if (line.Contains("confTrain2"))
{
locationTrain2 = RetrieveValueInDataFile.locationTrain(line);
}
else
{
distanceBetweenThem =RetrieveValueInDataFile.distBetweenTrain(line);
}
I wonder to have something like :
int [,] locations = new int [noLoc, 3]
{
{locationTrain1, locationTrain2, distanceBetweenThem}
{locationTrain1, locationTrain2, distanceBetweenThem}
{etc}
}
The problem is I have no idea how to do this in the StreamReader. I mean, how can I add the two locations and the distance (the syntax)?

You can only use such array initialization syntax when constructing array.
If you need to set values of an existing array (as in your sample) - use indexing:
int [,] locations = new int [noLoc, 3]
var rowIndex = 0;
using(StreamReader sr = new StreamReader(myTextFile))
{
while(
rowIndex < noLoc && // if using array you have to read no more than allocated
(line = sr.ReadLine()) != null)
{
locations[rowIndex,0] = locationTrain1;
locations[rowIndex,1] = locationTrain2;
locations[rowIndex,2] = distanceBetweenThem;
rowIndex++;
}
}
Note that it would likely be better to define class that holds this values and store them in a List as you read them.

Related

c# how to store values from a file in an array [duplicate]

This question already has answers here:
C# parsing a text file and storing the values in an array
(3 answers)
Closed 5 years ago.
I am trying to store values in an array from reading from a file. I have the reading from a file part but I can't get it to store in an array because it gives me an error "Value cannot be null" because after the loop the value of my variable becomes null and the array cannot be null. Here's what I have. And I realize that the for loop probably isn't in the correct spot so any help with where to put it would be great.
Program p = new Program();
int MAX = 50;
int[] grades = new int[MAX];
string environment = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "\\";
string path = environment + "grades.txt";
StreamReader myFile = new StreamReader(path);
string input;
int count = 0;
do
{
input = myFile.ReadLine();
if (input != null)
{
WriteLine(input);
count++;
}
} while (input != null);
for (int i = 0; i < count; i++)
{
grades[i] = int.Parse(input);
}
You start the for loop just after exiting from the while loop. And the condition to exit from the while loop is true when input is null. Of course this is not well accepted by Int.Parse.
Instead you can use a single loop, taking in consideration that you don't want to loop more than 50 times otherwise you exceed the array dimensions
int count = 0;
while((input = myFile.ReadLine()) != null && count < 50)
{
WriteLine(input);
grades[count] = int.Parse(input);
count++;
}
However you can have a more flexible way to handle your input if you use a List<int> instead of an array of integers. In this way you don't have to check for the number of lines present in your file
List<int> grades = new List<int>();
while((input = myFile.ReadLine()) != null)
grades.Add(int.Parse(input));
if we want to get really condensed
var grades = File.ReadAllLines(path).Select(l=>Int.Parse(l)).ToArray();
Utilize the Path.Combine() to help you in concatenating paths.
string environment = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
String fullPath = Path.Combine(environment, "grades.txt");
int[] grades = File.ReadAllLines(fullPath).Select(p => int.Parse(p)).ToArray<int>();
Console.WriteLine(grades);
Refer to https://www.dotnetperls.com/file-readalllines on how to use File.ReadAllLines() its very handy.
I'm using LINQ here, which sometimes simplifies things. Even though it looks a bit intimidating now. We read all lines, the result of that is then parsed by selecting each one and converting it to an integer then outputting an array of integers and saving that to grades.
Program p = new Program();
int MAX = 50;
int[] grades = new int[MAX];
string environment = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "\\";
string path = environment + "grades.txt";
using (StreamReader myFile = new StreamReader(path))
{
string input;
int count = 0;
while((!myFile.EndOfStream) && (count < MAX))
{
input = myFile.ReadLine();
if (!String.IsNullOrWhiteSpace(input))
{
WriteLine(input);
grades[count] = int.Parse(input);
count++;
}
}
}
You should definitely use the "using" pattern around your stream object. Got rid of the for-loop for you while maintaining mostly your code and style. Your issue was that you weren't using the input value before moving on to the next line. You only ever had the last value in your original code.

How to restart StreamReader to start reading from the beginning of a file

So i have to write a program that reads values (numbers) from Values.txt file and store them into array of integers (at the beginning i dont know the number of values in file so i dont know the length of array).
First i loop through the file and use counter variable to get the number of values to store into array. Then comes the problem, i dont know how to start from the beginning of file to catch values and store them into array.
When i run it i get 0 0 0 0 0 as a result.
If instead of
myReader.DiscardBufferedData();
myReader.BaseStream.Seek(0, SeekOrigin.Begin);
myReader.BaseStream.Position = 0;
I use the myReader.Close() and then myReader = new StreamReader("Values.txt), the result is correct, can somebody please explain why this is happening and howcan i fix this code :)
string lineOfText = "";
int counter = 0;
int[] intArray;
StreamReader myReader = new StreamReader("Values.txt");
while(lineOfText != null)
{
lineOfText = myReader.ReadLine();
if(lineOfText != null)
{
counter++;
}
}
intArray = new int[counter];
myReader.DiscardBufferedData();
myReader.BaseStream.Seek(0, SeekOrigin.Begin);
myReader.BaseStream.Position = 0;
counter = 0;
while(lineOfText != null)
{
lineOfText = myReader.ReadLine();
if (lineOfText != null)
{
intArray[counter] = int.Parse(lineOfText);
}
counter++;
}
myReader.Close();
for (int j = 0; j < intArray.Length; j++)
{
Console.WriteLine(intArray[j]);
}
This explains how to reset the stream if you want to do it in one pass Return StreamReader to Beginning.
Are you required to use an array? A list would be perfect for what your doing, you can then later push that list into an array or just work directly from the list. Code example below:
List<string> ints = new List<string>();
using (StreamReader sr = new StreamReader("example.txt"))
{
ints.Add(sr.ReadLine());
}

unable to convert string to int when using streamreader

I am having trouble converting a string to an int. Ive looked around and have been told to use the int.Parse but it isn't helping.
I have created an object Winner that has a int WinnerScore and string WinnerName.
I am trying to add these values to an array Winner[] before sorting them.
When I run this code it says:
NullReferenceException was unhandled
Object reference not set to an instance of an object.
Any idea why this is happening?
StreamReader sr = new StreamReader("highscores.txt");
for (int u = 0; u < nWinners; u++)
{
unsortedList[u].WinnerScore = int.Parse(sr.ReadLine());
unsortedList[u].WinnerName = sr.ReadLine();
}
sr.Close();
With a certain confidence I can suppose that you have declared the array unsortedList but you haven't initialized the objects of Winner class that you want to store in that array.
Simply declaring
Winner[] unsortedList = new Winner[100];
creates an array that could store 100 instances of Winner but this array is empty, there are no instances of a Winner class in the 100 slots available, they are all null. You should create every single Winner instances that you want to store in the 100 slots of the array.
So, as an example, your code could be rewritten as
Winner[] unsortedList = new Winner[nWinners];
using(StreamReader sr = new StreamReader("highscores.txt"))
{
for (int u = 0; u < nWinners; u++)
{
Winner w = new Winner();
w.WinnerScore = int.Parse(sr.ReadLine());
w.WinnerName = sr.ReadLine();
unsortedList[u] = w;
}
sr.Close();
}
However, this has the drawback that you need to know, before entering the loop, the exact number of Winner objects required to dimension your array, If, for some reason, you fail to count them correctly, you fall in another problem (Index Out Of Range).
In this case it is always better to use a List<Winner> where you don't need to know before hand the exact number of elements
List<Winner> unsortedList = new List<Winner>();
using(StreamReader sr = new StreamReader("highscores.txt"))
{
while((line = sr.ReadLine()) != null))
{
Winner w = new Winner();
w.WinnerScore = int.Parse(line);
w.WinnerName = sr.ReadLine();
unsortedList.Add(w);
}
sr.Close();
}
You've left creation as well as initialization:
// My suggestion of unsortedList generic type
public struct Winner {
public int WinnerScore;
public String WinnerName;
}
...
// 1. You shoud create unsortedList:
List<Winner> unsortedList = new List<Winner>();
// 2. You should also initialize the list with Winner instances
for (int u = 0; u < nWinners; ++u)
unsortedList.Add(new Winner());
// 3. Only that you can fill unsortedList from file.
// And you original code becames the correct one
using (StreamReader sr = new StreamReader("highscores.txt")) {
for (int u = 0; u < nWinners; ++u) {
unsortedList[u].WinnerScore = int.Parse(sr.ReadLine());
unsortedList[u].WinnerName = sr.ReadLine();
}
}
var unsortedList = new List<Winner>();
var nWinners = 100;
using (StreamReader sr = new StreamReader("highscores.txt"))
{
for (int i = 0; i < nWinners; i++)
{
var winer = new Winner();
winer.WinnerScore = int.Parse(sr.ReadLine());
winer.WinnerName = sr.ReadLine();
unsortedList.Add(winer);
}
sr.Close();
}

How to read from a file using C# code?

I have a file contains two lines . and in which line there is a double parameter .
I want to read both lines from the file and save them in an array of doubles .
I used the C# code below , but It doesn't work . It doesn't read anything and the array is empty after running the code .
Anybody has any idea where did I do wrong ?
Thanks for help .
private FileStream input;
double[] arr;
int i = 1;
input = new FileStream(Application.StartupPath+"\\City.txt", FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(input);
while (!reader.EndOfStream)
{
arr[i] = Convert.ToDouble(reader.ReadLine());
i++;
}
reader.Close();
This is a complete example of what you are doing.
string line;
List<double> values = new List<double>();
string path = Path.Combine(Application.StartupPath, "City.txt");
System.IO.StreamReader file = new System.IO.StreamReader(path);
while((line = file.ReadLine()) != null)
{
values.Add(double.Parse(line));
}
file.Close();
Based on "How to: Read a Text File One Line At a Time (MSDN)"
try this approach
using (StreamReader sr = File.OpenText(Application.StartupPath+"\\City.txt"))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
arr[i] = Convert.ToDouble(line);
i++;
}
}
and you should at least initialize arr: arr = new double[_size] and i should be zero because arrays in c# are zero based. And better use generic collection like List<T>(List<double> in this case).
The issue is while (!reader.EndOfStream) because when you initially read it in the position is at the end of the file. This is solidified by the fact that the line arr[i] should fail because you've not initialized the array (in fact, it shouldn't even compile...). So, how about this:
double[] arr = new double[2];
...
reader.BaseStream.Position = 0;
while (!reader.EndOfStream)
{
arr[i] = Convert.ToDouble(reader.ReadLine());
i++;
}
However, a more straight forward approach would be something like this:
var arr = new List<double>();
var lines = File.ReadAllLines(Application.StartupPath+"\\City.txt");
foreach (var l in lines)
{
arr.Add(Convert.ToDouble(l));
}
return arr.ToArray();
Another option is use File.ReadAllLines, considering that file size is small.
string[] stringDoubles = File.ReadAllLines(path, Encoding.UTF8);
for(int i=0;i<stringDoubles.Length;i++)
arr[i] = Convert.ToDouble(stringDoubles[i]);
The code as you posted will not compile, because you have not initialized your array, as well as having a visibility modifier on your FileStream. I'd guess this code is from two different locations in your project.
However, there's a much simpler way to do this: File.ReadAllLines
string path = #"c:\dev\text.txt"; //your path here
string[] lines = File.ReadAllLines(path);
double[] doubles = new double[2];
for (int i = 0; i < doubles.Length; i++)
{
double d;
if (double.TryParse(lines[i], out d))
doubles[i] = d;
}

Remove Duplicate Lines From Text File?

Given an input file of text lines, I want duplicate lines to be identified and removed. Please show a simple snippet of C# that accomplishes this.
For small files:
string[] lines = File.ReadAllLines("filename.txt");
File.WriteAllLines("filename.txt", lines.Distinct().ToArray());
This should do (and will copy with large files).
Note that it only removes duplicate consecutive lines, i.e.
a
b
b
c
b
d
will end up as
a
b
c
b
d
If you want no duplicates anywhere, you'll need to keep a set of lines you've already seen.
using System;
using System.IO;
class DeDuper
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Usage: DeDuper <input file> <output file>");
return;
}
using (TextReader reader = File.OpenText(args[0]))
using (TextWriter writer = File.CreateText(args[1]))
{
string currentLine;
string lastLine = null;
while ((currentLine = reader.ReadLine()) != null)
{
if (currentLine != lastLine)
{
writer.WriteLine(currentLine);
lastLine = currentLine;
}
}
}
}
}
Note that this assumes Encoding.UTF8, and that you want to use files. It's easy to generalize as a method though:
static void CopyLinesRemovingConsecutiveDupes
(TextReader reader, TextWriter writer)
{
string currentLine;
string lastLine = null;
while ((currentLine = reader.ReadLine()) != null)
{
if (currentLine != lastLine)
{
writer.WriteLine(currentLine);
lastLine = currentLine;
}
}
}
(Note that that doesn't close anything - the caller should do that.)
Here's a version that will remove all duplicates, rather than just consecutive ones:
static void CopyLinesRemovingAllDupes(TextReader reader, TextWriter writer)
{
string currentLine;
HashSet<string> previousLines = new HashSet<string>();
while ((currentLine = reader.ReadLine()) != null)
{
// Add returns true if it was actually added,
// false if it was already there
if (previousLines.Add(currentLine))
{
writer.WriteLine(currentLine);
}
}
}
For a long file (and non consecutive duplications) I'd copy the files line by line building a hash // position lookup table as I went.
As each line is copied check for the hashed value, if there is a collision double check that the line is the same and move to the next. (
Only worth it for fairly large files though.
Here's a streaming approach that should incur less overhead than reading all unique strings into memory.
var sr = new StreamReader(File.OpenRead(#"C:\Temp\in.txt"));
var sw = new StreamWriter(File.OpenWrite(#"C:\Temp\out.txt"));
var lines = new HashSet<int>();
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
int hc = line.GetHashCode();
if(lines.Contains(hc))
continue;
lines.Add(hc);
sw.WriteLine(line);
}
sw.Flush();
sw.Close();
sr.Close();
I am new to .net & have written something more simpler,may not be very efficient.Please fill free to share your thoughts.
class Program
{
static void Main(string[] args)
{
string[] emp_names = File.ReadAllLines("D:\\Employee Names.txt");
List<string> newemp1 = new List<string>();
for (int i = 0; i < emp_names.Length; i++)
{
newemp1.Add(emp_names[i]); //passing data to newemp1 from emp_names
}
for (int i = 0; i < emp_names.Length; i++)
{
List<string> temp = new List<string>();
int duplicate_count = 0;
for (int j = newemp1.Count - 1; j >= 0; j--)
{
if (emp_names[i] != newemp1[j]) //checking for duplicate records
temp.Add(newemp1[j]);
else
{
duplicate_count++;
if (duplicate_count == 1)
temp.Add(emp_names[i]);
}
}
newemp1 = temp;
}
string[] newemp = newemp1.ToArray(); //assigning into a string array
Array.Sort(newemp);
File.WriteAllLines("D:\\Employee Names.txt", newemp); //now writing the data to a text file
Console.ReadLine();
}
}

Categories