String array GetLength(1) working alternative - c#

I'm using System.IO.File.ReadAllLines to read a .txt file.
It returns a string[], but a human could also call it a 2D char array, which is exactly what I'm trying to put it into. I'm trying to find out the second dimension of this array, as abstracted as possible.
string[] textFile = System.IO.File.ReadAllLines(path);
char[,] charGrid = new char[textFile.GetLength(0), textFile.GetLength(1)];
IndexOutOfRangeException: Index was outside the bounds of the array.
I know I could loop through the array and find the length of the second dimension myself, but I'm looking for a solution that is simple, readable and abstracted.
ps: my input txt file:
#111
1-1
-00
10-

You'd need to find the Length of the longest line in the file (as this approach essentially gives you a jagged array). This can be done with the following bit of code:
int dimension = textFile.Max(line => line.Length);
You'll need to add using System.Linq; in order to useMax, which will return the value of the largest Length of all strings in the textFile array.
Then just plop dimension (or whatever you want to call it) into your char array declaration.
char[,] charGrid = new char[szTest.Length, dimension];

This solution assumes each row has the same number of char.
using System;
using System.IO;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
String path = #"input.txt";
string[] textFile = File.ReadAllLines(path);
char[,] charGrid = new char[textFile.Length, textFile[0].Length];
int i, j;
i = 0;
foreach (string line in textFile)
{
j = 0;
foreach (char c in line)
{
charGrid[i, j] = c;
j++;
}
i++;
}
Console.WriteLine(charGrid[0,0] + "" + charGrid[0, 1] + "" + charGrid[0, 2]);
Console.WriteLine(charGrid[1, 0] + "" + charGrid[1, 1] + "" + charGrid[1, 2]);
Console.WriteLine(charGrid[2, 0] + "" + charGrid[2, 1] + "" + charGrid[2, 2]);
Console.ReadLine();
}
}
}

Related

Odd System.IndexOutOfRangeException when trying to overwrite .txt file c#

I want to extend a data collection in a .txt file.
I'm reading a .txt file into a string array. Then I'm making a new string array with 5 more elements.
string oldarray[] = File.ReadAllLines(targetfile); //it is correctly reading the file
string newarray[] = new string[oldarray.Count()+5];
for (int i = 0; i < oldarray.Count(); i++) { //copy old array into new bigger one
newarray[i] = oldarray[i];
}
newarray[oldarray.Count() + 1] = "Data1"; //fill new space with data
newarray[oldarray.Count() + 2] = "Data2";
newarray[oldarray.Count() + 3] = "Data3";
newarray[oldarray.Count() + 4] = "Data4";
newarray[oldarray.Count() + 5] = " "; //spacer
//now write new array into same textfile over old data
File.WriteAllLines(targetfile, newarray); //System.IndexOutOfRangeException
I also tried writing line by line to the file like so, but it did just spit out the same exception:
using (StreamWriter writer = new StreamWriter(destinationFile)) //System.IndexOutOfRangeException
{
for (int i = 0; i < newarray.Length; i++)
{
writer.WriteLine(newarray[i]);
}
}
Why does it do that, and how do I fix it?
You're off by one - the last element in olaArray is at oldarray.Count() - 1, not oldarray.Count()
for (int i = 0; i < oldarray.Count(); i++){ //copy old array into new bigger one
newarray[i] = oldarray[i];
}
newarray[oldarray.Count()] = "Data1"; //fill new space with data
newarray[oldarray.Count() + 1] = "Data2";
newarray[oldarray.Count() + 2] = "Data3";
newarray[oldarray.Count() + 3] = "Data4";
newarray[oldarray.Count() + 4] = " "; //spacer
Array indexes are zero-based so oldarray.Count() + 5 points to an element after the end of the array. The first element is left empty too.
This could be fixed by fixing the indexes to be between 0 and 4 instead of 1 and 5. A better solution though would be to load the lines as a list and append the new strings :
string lines = File.ReadLines(targetfile).ToList();
var newLines=new[] {"Data1","Data2"...};
lines(newLines);
File.WriteAllLines(targetfile, lines);
Or even
var newLines=....;
string lines = File.ReadLines(targetfile)
.Concat(newLines)
.ToList();
File.WriteAllLines(targetfile, lines);
ReadAllLines uses a List as well and returns a copy of the list as an array. ReadLines on the other hand, returns lines one at a time as an IEnumerable<string>. The file remains open as long as the IEnumerable is iterated, so we need ToList() to consume it and allow the file to close before overwriting it.
The index oldarray.Count() + 5 does not exist in your new array.
Array indexing starts from zero. If you have an array with 10 elements then the first index is 0 and the last index is 9. If you make a new array with oldarray.Count() + 5 items it'll have 15 items and the last index will be 14 (not oldArray.Count + 5 which equals 15).
Just do like this:
newarray[oldarray.Count()] = "Data1";
newarray[oldarray.Count() + 1] = "Data2";
newarray[oldarray.Count() + 2] = "Data3";
newarray[oldarray.Count() + 3] = "Data4";
newarray[oldarray.Count() + 4] = " ";

Reading CSV of unknown number of rows/columns into Unity array

I want a 2D array generated from a CSV file with unknown number of rows/columns. The column count is fixed based on the header data. I need to be able to process it as a grid going both across rows and down columns hence needing array.
At the moment, I can split the data into rows, then split each row into components. I then add each row to a list. This all seems to work fine.
What I cant do is convert a list of string arrays into a 2d array.
It currently is failing on the line string[,] newCSV = csvFile.ToArray(); with error Cannot implicitly convert type 'string[][]' to 'string[ * , * ]' so I'm obviously not declaring something properly - I've just no idea what!
List<string[]> csvFile = new List<string[]>();
void Start()
{
// TODO: file picker
TextAsset sourceData = Resources.Load<TextAsset>("CSVData");
if (sourceData != null)
{
// Each piece of data in a CSV has a newline at the end
// Split the base data into an array each time the newline char is found
string[] data = sourceData.text.Split(new char[] {'\n'} );
for (int i = 0; i < data.Length; i ++)
{
string[] row = data[i].Split(new char[] {','} );
Debug.Log(row[0] + " " + row[1]);
csvFile.Add(row);
}
string[,] newCSV = csvFile.ToArray();
} else {
Debug.Log("Can't open source file");
}
Since your data is in the form of a table, I highly suggest using a DataTable instead of a 2d array like you're currently using to model/hold the data from your csv.
There's a ton of pre baked functionality that comes with this data structure that will make working with your data much easier.
If you take this route, you could then also use this which will copy CSV data into a DataTable using the structure of your CSV data to create the DataTable.
It's very easy to configure and use.
Just a small tip, you should always try to use data structures that best fit your task, whenever possible. Think of the data structures and algorithms you use as tools used to build a house, while you could certainly use a screw driver to pound in a nail, it's much easier and more efficient to use a hammer.
You can use this function to get 2d array.
static public string[,] SplitCsvGrid(string csvText)
{
string[] lines = csvText.Split("\n"[0]);
// finds the max width of row
int width = 0;
for (int i = 0; i < lines.Length; i++)
{
string[] row = SplitCsvLine(lines[i]);
width = Mathf.Max(width, row.Length);
}
// creates new 2D string grid to output to
string[,] outputGrid = new string[width + 1, lines.Length + 1];
for (int y = 0; y < lines.Length; y++)
{
string[] row = SplitCsvLine(lines[y]);
for (int x = 0; x < row.Length; x++)
{
outputGrid[x, y] = row[x];
// This line was to replace "" with " in my output.
// Include or edit it as you wish.
outputGrid[x, y] = outputGrid[x, y].Replace("\"\"", "\"");
}
}
return outputGrid;
}

Populate 2D arrays using a loop

I'm attempting to parse a pipe delimited line of text from a file - HL7 message segment - to make the segment a property of an HL7 message object.
I think I"m fundamentally not understanding the concept of n-dimensional arrays...
The segment looks like this
MSH|^~\&||X530^X530^FID|ERIC^NSCC^RSSI|NSCCH|....
I want to create an array thusly;
First item in the array = {"0","MSH"}
Next item in the array = {"1,", "^~\&"}
Next item in the array = {"2,", null}
Next item in the array = {"3,", "X530^X530^FID"}
I get error message:
private string [,] ParseSegment(string ms)
{
int i = 0;
string[] segmentFields = ms.Split('|');//fields for this segment
int arrayLength = segmentFields.Length;
string[,] fieldAndIndex = new string[arrayLength,1];
foreach (string field in segmentFields)
{
fieldAndIndex [i,i] = {{ i,field} };//I'm not sure what to do here!!!!
}
return fieldAndIndex;
}
Each sub array of your 2D array has 2 items (right?), so you should have a 2 instead of a 1 as the length:
string[,] fieldAndIndex = new string[arrayLength, 2];
Since you want a counter variable I in the loop, you should not use a foreach loop:
for (int i = 0 ; i < arrayLength ; i++) {
// here you want the first item of the subarray to be i, and the second item to be the corresponding segment
fieldAndIndex[i, 0] = i.ToString();
fieldAndIndex[i, 1] = segmentFields[i];
}
Also, I don't think a 2D array is suitable here. Storing the index of each element (which is what you seem to be trying to do) is unnecessary, because fieldAndIndex[x, 0] will always be the same as x!
You might want to use a simple 1D array instead. There are other data structures that might be useful:
Dictionary<int, string>
(int, string)[]
string[][]
To understand the basic array in your case you can consider the array to be a 2D Matrix. Similarly you can consider a 3D array a cube. What you are trying to do is add two item in one place
fieldAndIndex [i,i] = {{ i,field} };
So during the first iteration the notation [i,i] evaluates to [0,0] which means the first element in the first row.
The proper way to insert these both can be done as shown by the given answer
fieldAndIndex [i,i] = i.ToString();
fieldAndIndex [i,++i] = field.ToString();
I hope this resolves your issue it is better to go through some research on multi dimensional arrays. This and This are some good links to get started on these arrays.
private string [] ParseSegment(string ms) //you do not need 2d array for that
{
int i = 0;
string[] segmentFields = ms.Split('|');//fields for this segment
int arrayLength = segmentFields.Length;
string[] fieldAndIndex = new string[arrayLength];
foreach (string field in segmentFields)
{
fieldAndIndex [i] = field;
i++;
}
return fieldAndIndex;
}
You do not need 2d array(matrix) to parse that (calling fieldAndIndex[n] will just give it's value - fieldAndIndex[1] == "^~\&""), but if you really need to :
private string [,] ParseSegment(string ms)
{
int i = 0;
string[] segmentFields = ms.Split('|');//fields for this segment
int arrayLength = segmentFields.Length;
string[,] fieldAndIndex = new string[arrayLength,2];
foreach (string field in segmentFields)
{
fieldAndIndex [i][0] = i;
fieldAndIndex [i][1] = field;
i++;
}
return fieldAndIndex;
}
While I dont understand why you would want a 2 dimentional array.
new string[arrayLength,1]; should be new string[arrayLength,2];
[i,i] expects 1 element, not 2. Also you need to use [i,0] and [i,1]
private string [,] ParseSegment(string ms)
{
int i = 0;
string[] segmentFields = ms.Split('|');//fields for this segment
int arrayLength = segmentFields.Length;
string[,] fieldAndIndex = new string[arrayLength,2];
foreach (string field in segmentFields)
{
fieldAndIndex [i,0] = i.ToString();
fieldAndIndex [i,1] = field;
i++;
}
return fieldAndIndex;
}

Searching for a string in a part of a multidimensional array c#

I need to find the location of a string in a part of a multidimensional array.
If you have:
string[,] exampleArray = new string[3,y]
Where 3 is the number of columns and y is the number of rows, I need to find the location of a string in the full y row but only in the second or third 'column'. So I want my program to search for the location of the string in [1,y] and [2,y].
One possible solution is to iterate your rows and check each column of index 1 and 2 on each row.
//Example array to search
string[,] exampleArray = new string[y,3]
//string to search for
string searchedString = "someValue";
//for-loop to iterate the rows, GetLength() will return the length at position 0 or (y)
for(int x = 0; x < exampleArray.GetLength(0); x++)
{
if(string.Equals(exampleArray[x, 1], searchedString))
{
//Do something
Console.Writeline("Value found at coordinates: " + x.ToString() + ", " + 1.ToString());
}
if(string.Equals(exampleArray[x, 2], searchedString))
{
//Do something
Console.Writeline("Value found at coordinates: " + x.ToString() + ", " + 2.ToString());
}
}

Defining Dynamic Array

How can I define a dynamic array in C#?
C# doesn't provide dynamic arrays. Instead, it offers List class which works the same way.
To use lists, write at the top of your file:
using System.Collections.Generic;
And where you want to make use of a list, write (example for strings):
List<string> mylist = new List<string>();
mylist.Add("First string in list");
Take a look at Array.Resize if you need to resize an array.
// Create and initialize a new string array.
String[] myArr = {"The", "quick", "brown", "fox", "jumps",
"over", "the", "lazy", "dog"};
// Resize the array to a bigger size (five elements larger).
Array.Resize(ref myArr, myArr.Length + 5);
// Resize the array to a smaller size (four elements).
Array.Resize(ref myArr, 4);
Alternatively you could use the List class as others have mentioned. Make sure you specify an initial size if you know it ahead of time to keep the list from having to resize itself underneath. See the remarks section of the initial size link.
List<string> dinosaurs = new List<string>(4);
Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);
dinosaurs.Add("Tyrannosaurus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Mamenchisaurus");
dinosaurs.Add("Deinonychus");
If you need the array from the List, you can use the ToArray() function on the list.
string[] dinos = dinosaurs.ToArray();
C# does provide dynamic arrays and dynamic array manipulation. The base of an array is dynamic and can be modified with a variable. You can find the array tutorial here (https://msdn.microsoft.com/en-us/library/aa288453%28v=vs.71%29.aspx). I have also included code that demonstrates an empty set array and a dynamic array that can be resized at run time.
class Program
{
static void Main(string[] args)
{
int x = Convert.ToInt32(Console.ReadLine());
int y = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(x);
{
int[] dynamicArray1 = { };//empty array
int[] numbers;//another way to declare a variable array as all arrays start as variable size
numbers = new int[x];//setting this array to an unknown variable (will be user input)
for (int tmpInt = 0; tmpInt < x; tmpInt++)//build up the first variable array (numbers)
{
numbers[tmpInt] = tmpInt;
}
Array.Resize(ref numbers,y);// resize to variable input
dynamicArray1 = numbers;//set the empty set array to the numbers array size
for (int z = 0; z < y; z++)//print to the new resize
{
Console.WriteLine(numbers[z].ToString());//print the numbers value
Console.WriteLine(dynamicArray1[z].ToString());//print the empty set value
}
}
Console.Write("Dynamic Arrays ");
var name = Console.ReadLine();
}
}
Actually you can have Dynamic Arrays in C# it's very simple.
keep in mind that the response to your question above is also correct you could declare a
List Generic
The way to Create a Dynamic Array would be to declare your Array for example
string[] dynamicArry1 = { };//notice I did not declare a size for the array
List<String> tmpList = new List<string>();
int i = 1;
for(int tmpInt = 0; tmpInt < 5; tmpInt++)
{
tmpList.Add("Testing, 1.0." + tmpInt + ", 200, 3.4" + tmpInt +"," + DateTime.Now.ToShortDateString());
//dynamicArry1[tmpInt] = new string[] { tmpList[tmpInt].ToCharArray() };
}
dynamicArry1 = tmpList.ToArray();
how about ArrayList ?
If I'm not wrong ArrayList is an implementation of dynamic arrays
Example of Defining Dynamic Array in C#:
Console.WriteLine("Define Array Size? ");
int number = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Enter numbers:\n");
int[] arr = new int[number];
for (int i = 0; i < number; i++)
{
arr[i] = Convert.ToInt32(Console.ReadLine());
}
for (int i = 0; i < arr.Length; i++ )
{
Console.WriteLine("Array Index: "+i + " AND Array Item: " + arr[i].ToString());
}
Console.ReadKey();
like so
int nSize = 17;
int[] arrn = new int[nSize];
nSize++;
arrn = new int[nSize];

Categories