Please can you help me?
I have to read from file these int:
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
3 15 0 2 22
9 18 13 17 5
19 8 7 25 23
20 11 10 24 4
14 21 16 12 6
14 21 17 24 4
10 16 15 9 19
18 8 23 26 20
22 11 13 6 5
2 0 12 3 7
The code I'm trying to use is this:
String input = File.ReadAllText( @"c:\myfile.txt" );
int i = 0, j = 0;
int[,] result = new int[5, 5];
foreach (var row in input.Split('\n'))
{
j = 0;
foreach (var col in row.Trim().Split(' '))
{
result[i, j] = int.Parse(col.Trim());
j ;
}
i ;
}
The problem is that in the input file there are too much spaces and the code get an exception. System.FormatException
How can I read matrix without these spaces?
CodePudding user response:
If you want to re-jig your code to using a jagged array:
You could, I suppose, read it as a stream of ints that you repartition into 5 columns based on the index of the int
int[][] matrix = File.ReadAllText(...)
.Split(Array.Empty<string>(), StringSplitOptions.RemoveEmptyEntries)
.Select((s, i) => new { N = int.Parse(s), I = i})
.GroupBy(at => at.I/5, at => at.N, (k, g) => g.ToArray())
.ToArray();
So, what's going on here?
- File.ReadAllText we know
- Split on an empty delimiter array causes Split to split on whitespace, so all your spaces, tabs, returns etc are just folded into being "a single delimiter" by RemoveEmptyEntries which effectively delivers the file contents as a list of numbers, having removed all the interim whitespace
- Select in this guise takes a lambda that accepts two parameters; one the number itself (as a string) that I've termed
sand the other,ithe index from 0 that it occurs at. These two bits of info are captured into an anonymous type asN(the result of parsingsto an int) andI - GroupBy here has 3 parameters, all lambdas
- The first is what to group by - in this case we're going to group by the
I divided by 5. This chops the number stream up into blocks of 5 ints - The second is what value goes into the output group - in this case there is no longer any need for I, so we just put N in the output. This means that the GroupBy will effectively make a list of a
list of 5 intsas its output - The third is what transform to apply to the resulting
list of 5 intsand I ToArray it, to make it anint[5]
- The first is what to group by - in this case we're going to group by the
- Because we now have a
list of int[5]all we need to do is call ToArray on it to turn it into anint[n][5]where n is the number of items in the list
In its current form, this is a 15x5, but if you wanted it as three 5x5 you could chop it again using a similar strategy, or perhaps a simpler Skip/Take 5 set inside a loop
Note that here I use the word "list" in its English sense, not in its List<T> C# sense, as a contraction of "enumerable collection"
CodePudding user response:
If you want to keep using the existing int[,] you can make life a bit easier by leveraging the fact that they're stored sequentially, so you could read your file into one array of ints, and then write chunks of it to a matrix
You appear to have three 5x5 matrix in the file but only capacity to store one in your code. This means your code will blow up after the first matrix is filled. Instead let's have a list for all our matriceS:
var allNums = x.Split(Array.Empty<string>(), StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
var matrices = new List<int[,]>();
for(int i = 0; i*25 < allNums.Length; i ){
var matrix = new int[5,5];
Buffer.BlockCopy(allNums, i*25*sizeof(int), matrix, 0, 25 * sizeof(int));
matrices.Add(matrix);
}
- The file is read into allNums using a similar strategy as mentioned in the other answer; RemoveEmptyEntries in combination with an empty delimiter list means that any numbers of whitespace in a row serve as one delimiter. This time we run
Select(int.Parse)to convert every string number in the stream of numbers from the file, into a stream of ints and store them in a single array - For as many blocks of 25 numbers as there are in the stream
- Make a new matrix to receive them
- Use BlockCopy to copy the bytes from portion X of the source array to 0, for length of (however many bytes 25 ints occupies). In practive this means that the bytes representing the first 25 numbers are copied to a matrix, then on the next loop the the next 25 are copied to another matrix..
- Add the matrix to a list of matrices
At the end of the operation, your list of matrices has three 5x5 inside
CodePudding user response:
If you want to persist with your existing code, it needs some fixup predominantly because it can only store one 5x5 matrix, and there are three such matrices in the file. The rest of my commentary is in the code as comments:
string[] lines = File.ReadAllLines(@"c:\myfile.txt" );
List<int[,]> matrices = new(); //to store three matrices in
int[,] result = new int[5, 5];
for(int i = 0; i < lines.Length; i ) //for loop is tidier than having i and j variables dumped all around the place in a foreach
{
//make the columns array now, so we can check it for length and skip if it's not 5
var cols = lines[i].Split(' ', StringSplitOptions.RemoveEmptyEntries);
if(cols.Length != 5) continue; //skip if it's wonky/blank line
//write the cols
for(int j = 0; j < cols.Length; j )
result[i%5, j] = int.Parse(cols[j]); //note that it's i%5 because i will increase forever, but this matrix needs it to stay in the range 0..4
//if we processed our last row for this matrix i.e. i%5 is 4, save the matrix and renew it
if(i % 5 == 4){
matrices.Add(result);
result = new int[5,5];
}
}
