Reputation: 25
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?
Upvotes: 0
Views: 1144
Reputation: 11201
Props @CaiusJard for the many variations. The following pipeline first regroups the input data (file) into a more sensible format, eg the text for only a single matrix. And then pipes that format through to the compute intensive method that does the actual parsing and array creation.
class Program
{
static void Main(string[] args)
{
var matrices =
File.ReadAllLines(...)
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select((line, i) => new { MatrixNumber = i/5, Line = line })
.GroupBy(x => x.MatrixNumber, x => x.Line)
.Select(group => ParseMatrix(group.ToList()))
.ToList();
...
}
static int[,] ParseMatrix(List<string> txtRows)
{
if (txtRows.Count != 5) throw new FormatException("Invalid dimension");
var matrix = new int[5,5];
for (var i=0; i<5; i++)
{
var columns = txtRows[i].Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (columns.Length != 5) throw new FormatException("Invalid dimension");
for (var j=0; j<5; j++)
{
matrix[i,j] = int.Parse(columns[j]);
}
}
return matrix;
}
}
The benifit in doing so is that, for very large files, we can easily add .AsParallel()
to make optimal use of computer resources. I also added AsOrdered()
assuming the order of the matrices in the file should be preserved.
var matrices =
File.ReadAllLines(...)
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select((line, i) => new { MatrixNumber = i/5, Line = line })
.GroupBy(x => x.MatrixNumber, x => x.Line)
.AsParallel()
.AsOrdered()
.Select(group => ParseMatrix(group.ToList()))
.ToList();
Upvotes: 0
Reputation: 74605
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];
}
}
Upvotes: 0
Reputation: 74605
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);
}
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 arrayAt the end of the operation, your list of matrices has three 5x5 inside
Upvotes: 1
Reputation: 74605
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?
s
and the other, i
the index from 0 that it occurs at. These two bits of info are captured into an anonymous type as N
(the result of parsing s
to an int) and I
I divided by 5
. This chops the number stream up into blocks of 5 intslist of 5 ints
as its outputlist of 5 ints
and I ToArray it, to make it an int[5]
list of int[5]
all we need to do is call ToArray on it to turn it into an int[n][5]
where n is the number of items in the listIn 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"
Upvotes: 2