I have a text file
0.4658 0 3
0.4095 0 3
0.4594 0 3
0.4297 0 3
0.3963 0 3
0.4232 0 3
0.4633 0 3
0.5384 0 3
0.5042 0 3
0.4328 0 3
that I want to read into a 2D double array that looks like this.
{{0.4658, 0, 3},
{0.4095, 0, 3},
... (and so on)
{0.4328, 0, 3}}
I have the following code:
public static void main(String[] args) throws Exception{
double[][] ref = null;
ref = matrix("data80.in",10,3);
}
public static double[][] matrix(String filename, int size1, int size2) throws Exception {
double[][] matrix = null;
BufferedReader buffer = new BufferedReader(new FileReader(filename));
String line;
int row = 0;
while ((line = buffer.readLine()) != null) {
String[] vals = line.trim().split("\\s+");
if (matrix == null) {
matrix = new double[size1][size2];
}
for (int col = 0; col < size1; col++) {
matrix[row][col] = Double.parseDouble(vals[col]);
}
row++;
}
buffer.close();
return matrix;
}
But it keeps giving me an outOfBounds exception, and I don't know where I am going wrong. Please help. If anyone has more efficient solutions as well to my problem it would be helpful
It's because of the following for loop:
for (int col = 0; col < size1; col++) {
matrix[row][col] = Double.parseDouble(vals[col]);
}
We are using size1 whereas we should be using size2, following would work:
for (int col = 0; col < size2; col++) {
matrix[row][col] = Double.parseDouble(vals[col]);
}
Also, there is no need for null check inside the for loop, you can remove it and initialise the array in the beginning, e.g.:
public static double[][] matrix(String filename, int size1, int size2) throws Exception {
double[][] matrix = new double[size1][size2];;
BufferedReader buffer = new BufferedReader(new FileReader(filename));
String line;
int row = 0;
while ((line = buffer.readLine()) != null) {
String[] vals = line.trim().split("\\s+");
for (int col = 0; col < size2; col++) {
matrix[row][col] = Double.parseDouble(vals[col]);
}
row++;
}
buffer.close();
return matrix;
}
You have defined you 2d matrix as
matrix = new double[size1][size2];
meaning there are size1 rows and size2 columns but in following line:
for (int col = 0; col < size1; col++) {
you have used size1. So correction is:
for (int col = 0; col < size2; col++) {
Here is yet another concept as to how you can place the delimited numerical data contained within a text file of any number of rows and any number of columns into a Double data type Two Dimensional Array. All you need to do is pass the path and file name to the method. You can also optionally supply the delimiter used within the file, the method default is a comma (,) delimiter since it is one of the most commonly used. Here is the method:
public static double[][] matrix(String filename, String... delimiterInFile) {
String delimiter = ","; // Default data delimiter in file.
// See if a optional data delimiter is supplied...
if (delimiterInFile.length > 0) { delimiter = delimiterInFile[0]; }
// Catch IO Exceptions
try {
//Place the contents of file into a ArrayList
List<String> list = Files.lines(Paths.get(filename)).collect(Collectors.toList());
// Get the greatest number of delimited columns contiained
// within the ArrayList the whole while ignoring blank lines
// (there could be blank lines in file). Our columns for our
// double 2D Array will be determined from this value. We also
// determine the true number of rows required (remember, no
// blank elements allowed so ArrayList.size() wont be good enough).
int r = 0, c = 0;
for (int i = 0; i < list.size(); i++) {
if (!list.get(i).equals("")) {
int l = list.get(i).split(delimiter).length;
if (l > c) { c = l; }
r++;
}
}
// If we have nothing then the get outta here
// by returning null.
if (r == 0 || c == 0) { return null; }
// Declare and initialize a double data type 2D Array
double[][] array = new double[r][c];
// Fill the double type array...
for (int i = 0; i < list.size(); i++) {
if (!list.get(i).equals("")) {
String[] data = list.get(i).split(delimiter);
for (int j = 0; j < data.length; j++) {
array[i][j] = Double.parseDouble(data[j]);
}
}
}
return array;
} catch (IOException ex) {
// Do what you want with the Exception...
ex.printStackTrace();
return null;
}
}
This method will automatically determine the required number of Rows and Columns for the returned Double data type 2D Array. The method ignores blank file lines so the required Rows needed for the returned Double 2D Array is determined with this in mind. The number of Columns value is determined by iterating through the data lines and detecting which data line contains the most delimited data. That column count is used for the entire 2D Array. This means then that file data lines which contain less columns will have their remaining Array Elements filled with a 0.0 double type value.
The optional delimiter that can be passed to this method can be any string or a RegEx (Regular Expression) string, for example: " " or "\\s+" or "," or ", " or "\t", etc.
This method will also throw an IO Exception should there be a problem accessing the supplied data file.
With the data file schema you provided:
0.4658 0 3
0.4095 0 3
0.4594 0 3
0.4297 0 3
0.3963 0 3
0.4232 0 3
0.4633 0 3
0.5384 0 3
0.5042 0 3
0.4328 0 3
and let's assume this file is named data.txt which is in your classpath, you might use this method like this:
double[][] myData = matrix("data.txt", "\\s+");
for (int i = 0; i < myData.length; i++) {
String strg = "";
for (int j = 0; j < myData[0].length; j++) {
strg+= myData[i][j] + " ";
}
System.out.println(strg);
}
Keep in mind, this is not a method I would recommend for really large data files (Hundreds of thousands of lines).
Related
I have some code for a 2D array but I don't want spaces at the end of each row before I start a new row. For some reason, I can't find where I'm messing up because a space is being put at the end of each row. Basically what I'm trying to do is input a 2D array and the output should make it look the same as the input, except for the {}'s and it'll be a string. For example,
Input:
{1, 2, 3},
{4, 5, 6};
Output:
1 2 3
4 5 6
public class Matrix {
// the dimensions of the matrix
private int numRows;
private int numColumns;
// the internal storage for the matrix elements
private int data[][];
/**
* #param d - the raw 2D array containing the initial values for the Matrix.
*/
public Matrix(int d[][])
{
// d.length is the number of 1D arrays in the 2D array
numRows = d.length;
if(numRows == 0)
numColumns = 0;
else
numColumns = d[0].length; // d[0] is the first 1D array
// create a new matrix to hold the data
data = new int[numRows][numColumns];
// copy the data over
for(int i=0; i < numRows; i++)
for(int j=0; j < numColumns; j++)
data[i][j] = d[i][j];
}
/**
* Returns a String representation of this Matrix.
*/
#Override // instruct the compiler that we intend for this method to override the superclass' (Object) version
public String toString() {
// TODO: replace the below return statement with the correct code.
String arrString = "";
for(int i = 0; i < data.length; i++) {
for(int j = 0; j < data[i].length; j++) {
arrString += data[i][j] + " ";
}
arrString += "\n";
}
return arrString;
}
Next time please post a runnable example.
Your problem was that you always added a space after the item, no matter if it was the last one in the line. I now check that with a conditional + (j == data[i].length - 1 ? "" : " ");
Hint: It's not good to concatenate Strings. Use StringBuilder for better performance an memory usage. I added a second method toString2() to show how it's done.
package stackoverflow;
public class Matrix {
// the dimensions of the matrix
private final int numRows;
private int numColumns;
// the internal storage for the matrix elements
private final int data[][];
/**
* #param d - the raw 2D array containing the initial values for the Matrix.
*/
public Matrix(final int d[][]) {
// d.length is the number of 1D arrays in the 2D array
numRows = d.length;
if (numRows == 0)
numColumns = 0;
else
numColumns = d[0].length; // d[0] is the first 1D array
// create a new matrix to hold the data
data = new int[numRows][numColumns];
// copy the data over
for (int i = 0; i < numRows; i++)
for (int j = 0; j < numColumns; j++)
data[i][j] = d[i][j];
}
/**
* Returns a String representation of this Matrix.
*/
#Override // instruct the compiler that we intend for this method to override the superclass' (Object) version
public String toString() {
// TODO: replace the below return statement with the correct code.
String arrString = "";
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
arrString += data[i][j] + (j == data[i].length - 1 ? "" : " ");
}
arrString += "\n";
}
return arrString;
}
public String toString2() {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
sb.append(data[i][j] + (j == data[i].length - 1 ? "" : " "));
}
sb.append("\n");
}
return sb.toString();
}
public static void main(final String[] args) {
final int[][] arr = new int[2][3];
arr[0][0] = 4;
arr[0][1] = 6;
arr[0][2] = 8;
arr[1][0] = 8;
arr[1][1] = 16;
arr[1][2] = 23;
final Matrix m = new Matrix(arr);
System.out.println("Matrix:\n" + m);
System.out.println("Matrix 2:\n" + m.toString2());
}
}
Output:
Matrix:
4 6 8
8 16 23
Matrix 2:
4 6 8
8 16 23
The Answer by JayC667 seems to correctly address your Question.
Stream, lambda, & method reference
For fun, here is an alternative approach using stream, lambda, and method reference.
Define the array.
int[][] input = { { 1 , 2 , 3 } , { 4 , 5 , 6 } }; // Declaration, initialization.
Make a stream where each element is a row, an array of int values, from your two-dimensional array.
For each of those rows, each being a int[], make a stream of its int primitive values (an IntStream), convert each primitive to an Integer object (boxing), call each Integer object’s toString method to generate a piece of text. Collect those pieces of text by joining them into a longer String with a SPACE character as a delimiter.
So we have transformed each row into a String. Collect all those strings together, with a LINE FEED character as the delimiter. Then, we are done, with a single String object as a result.
All that work, in a single line of code!
String result =
Arrays
.stream( input ) // A series of integer arrays, etc element being a int[].
.map( // Convert each integer array into something else, a `String` object.
( int[] row ) -> Arrays.stream( row ).boxed().map( Object :: toString ).collect( Collectors.joining( " " ) )
)
.collect( Collectors.joining( "\n" ) ); // Join each row of text with the next, using Linefeed as delimiter.
Results.
1 2 3
4 5 6
Here is one way to return a formatted 2D array based on the anticipated width of the values.
%nd - specifies a field width of n digits, right aligned.
%-nd - specifies a field width of n digits, left aligned (would have spaces at end of line).
fields will be filled in with spaces where necessary.
public class TwoDtoString {
int[][] mat = { { 11, 222, 3333 }, { 433, 53, 633 }, { 73, 8, 9333 } };
static String FORMAT = "%5d"; // 5 digit field, right aligned.
public static void main(String[] args) {
TwoDtoString tos = new TwoDtoString();
System.out.println(tos.toString());
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int[] row : mat) {
sb.append(FORMAT.formatted(row[0]));
for (int i = 1; i < row.length; i++) {
sb.append(FORMAT.formatted(row[i]));
}
sb.append("\n");
}
return sb.toString();
}
}
prints
11 222 3333
433 53 633
73 8 9333
I currently have a text file in the format
matrix
row
a
b
c
row
d
e
f
row
g
h
i
row
j
k
l
matrix
row
m
n
o
p
q
row
r
s
t
u
v
I would like to convert this into two integer matrices (stored as 2 2D arrays), in the format
a b c
d e f
g h i
j k l
and
m n o p q
r s t u v
So far, I have created a Scanner object of the file and put each line in a text array:
Scanner sf = new Scanner(new File("C:\\textfiles\\matrices.txt"));
int maxIndex = -1;
String text[] = new String[10000]; // I added more than necessary for safety
while (sf.hasNext()){
maxIndex++;
text[maxIndex] = sf.nextLine();
}
sf.close();
This way, the text file is now contained in a string array, where each line is a new element of the array. Right now, I would like to partition the array into two arrays with each array being the matrices. How should I continue? (note: I am a total beginner and desire answers that are simple (no arraylist, hashmap, etc., and that's why this question is not a duplicate of How to read two matrices from a txt file in java because it uses BufferedReader, and there are other potential duplicate questions, so I would like to clear this up)
What I currently have after the top:
int counter = 0;
int iCounter = 0; // row
int jCounter = 0; // column
int matrix1[][];
int matrix2[][];
while (counter < maxIndex){
if (counter = 0)
{
\\not yet written...
}
\\not yet written...
}
As #Rob said, it's really cumbersome to do this without dynamic data structures such as ArrayList's. But nevertheless, here's a code that does your job (considering you have only two matrices), without using any List's:
int counter = 0;
int iCounter = 0; // row
int jCounter = 0; // column
int matrix1[][];
int matrix2[][];
int rowSize = 0, numberOfRows = 0;
counter = 2;
while (!text[counter].equals("row") && !text[counter].equals("matrix")) {
counter++;
rowSize++;
}
//now we have the row size
numberOfRows = 1;
while (!text[counter].equals("matrix")) {
if (text[counter].equals("row"))
numberOfRows++;
counter++;
}
//now we have the total number of rows
matrix1 = new int[numberOfRows][rowSize];
counter = 2; //to start from the first matrix
//now counter should point to the first row of the first matrix
while (!text[counter].equals("matrix")) {
jCounter = 0;
while (!text[counter].equals("row")
&& !text[counter].equals("matrix")) {
matrix1[iCounter][jCounter++] = Integer.parseInt(text[counter]);
//supposing your input is Integers, otherwise, you can change
//it to the corresponding type (i.e. Long, Double, etc)
counter++;
}
iCounter++;
if (!text[counter].equals("matrix"))
counter++;
}
//now we finished with the first matrix, and the counter points to
//the first "row" of the second matrix, so we do the same thing again
rowSize = 0;
numberOfRows = 0;
int startOfSecondMatrix = counter + 2; //save this for later
counter += 2; // so that counter points to the first number
while (counter < text.length && !text[counter].equals("row")) {
counter++;
rowSize++;
}
numberOfRows = 1;
while (counter < text.length) {
if (text[counter].equals("row"))
numberOfRows++;
counter++;
}
matrix2 = new int[numberOfRows][rowSize];
counter = startOfSecondMatrix;
iCounter = 0;
while (counter < text.length) {
jCounter = 0;
while (counter < text.length && !text[counter].equals("row")) {
matrix2[iCounter][jCounter++] = Integer.parseInt(text[counter]);
counter++;
}
iCounter++;
counter++;
}
For each matrix we perform the same operations:
-We first go through the matrix to count its size to be able to initialize it, after that, we go row by row, and parse each number.
You might as well put all the work for one matrix into a function (and take care of the bounds) and call it as long you still have more matrices.
This does what you want. Unfortunately doing this with 2D arrays is considerably harder since once you set the size of an array its difficult to manage changing it. Therefore using ArrayList is much easier.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Main {
public static final String MATRIX = "matrix";
public static final String ROW = "row";
public static void main(String[] args) throws FileNotFoundException {
// Use correct file name here
Scanner sf = new Scanner(new File("matrices.txt"));
// This is a List of 2D Lists
List<List<List<String>>> matrices = new ArrayList<>();
// easier to process lines as we're reading them in so we
// only iterate over the file once
while (sf.hasNext()) {
boolean hasBeenProcessed = false;
String inputValue = sf.nextLine();
switch (inputValue) {
case MATRIX:
ArrayList<List<String>> matrix = new ArrayList<>();
matrices.add(matrix);
hasBeenProcessed = true;
break;
case ROW:
List<List<String>> currentMatrix = getMatrixBeingProcessed(matrices);
currentMatrix.add(new ArrayList<String>());
hasBeenProcessed = true;
break;
}
if (!hasBeenProcessed) {
List<List<String>> currentMatrix = getMatrixBeingProcessed(matrices);
List<String> currentRow = getCurrentRow(currentMatrix);
currentRow.add(inputValue);
}
}
// Print out the results:
int i = 1;
for (List<List<String>> matrix : matrices) {
System.out.println("Matrix " + i);
for (List<String> row : matrix) {
for (String element : row) {
System.out.print(element + " "); // no newline until end of the row
}
System.out.println(); // new line
}
i++;
System.out.println(); // new line
}
}
private static List<String> getCurrentRow(List<List<String>> currentMatrix) {
int lastRow = currentMatrix.size() - 1;
return currentMatrix.get(lastRow);
}
private static List<List<String>> getMatrixBeingProcessed(List<List<List<String>>> matrices) {
int lastMatrix = matrices.size() - 1;
List<List<String>> currentMatrix = matrices.get(lastMatrix);
return currentMatrix;
}
}
Output:
Matrix 1
a b c
d e f
g h i
j k l
Matrix 2
m n o p q
r s t u v
Process finished with exit code 0
Since you don't want to use List and arrays can't be resized once initialized, this is not easy.
There are two ways: Read the file and initialize arrays knowing the size (as #Maaddy posted) or 'resizing' arrays. That's not possible but it is if you use Arrays.copyOf() so you can create a new array.
The idea is create a 'tridimensional' array where you can store: matrix, row and column; and then start to read the file.
Every time you find a word the entire array will be updated creating a new array with one length more.
If the word is 'matrix' the extra length will be added to the first position (the position who 'store' the matrix)
If the word is 'row' then the space will be added for the current matrix. So in this way, the current matrix will have one more array where store the column values.
If the word is other then is a value for the column. The column is resized and added to the correct position.
Note that if a word 'matrix' or 'row' is found, the new array is initialized with no length. This is because will be resized later, when is necessary.
The code is as follows:
//Initialize array with no positions
String[][][] arrays = new String[0][0][0];
Scanner sf = new Scanner(new File("path/matrices.txt"));
int matrix = -1;
int row = -1;
int column = -1;
while (sf.hasNext()){
String line = sf.nextLine();
if(line.equals("matrix")) {
//'Resize' array: Create new array with 1 more length and old data
arrays = Arrays.copyOf(arrays, arrays.length + 1);
//Start new matrix
arrays[++matrix] = new String[0][0];
row = -1;
column = -1;
}else if(line.equals("row")) {
//'Resize' matrix: Create a new array with 1 more length and old data
arrays[matrix] = Arrays.copyOf(arrays[matrix], arrays[matrix].length+1);
row++;
arrays[matrix][row] = new String[0];
column = -1;
}else{
//'Resize' matrix
column++;
arrays[matrix][row] = Arrays.copyOf(arrays[matrix][row], arrays[matrix][row].length+1);
arrays[matrix][row][column] = line;
}
}
sf.close();
//Print result
for(int i = 0 ; i < arrays.length; i++) {
System.out.println("Matrix "+i);
for(int j = 0; j < arrays[i].length; j++ ) {
for(int k = 0; k < arrays[i][j].length; k++) {
System.out.print(arrays[i][j][k]+ " ");
}
System.out.println();
}
System.out.println();
}
And the result is:
Matrix 0
a b c
d e f
g h i
j k l
Matrix 1
m n o p q
r s t u v
String[][] array = {{"abcd",""},{"asdf",""},{"",""},{"",""},{"",""},{"",""}};
I want to remove the {"",""} elements from the array.
How can I do it in Java?
Remove?
You cannot change the size of an existing array.
If you want to create a new array with only these elements, count the length of each array, create a new array based on those lengths, add elements to the new array.
String[][] array= {{"abcd",""},{"asdf",""},{"",""},{"",""},{"",""},{"",""}};
//Assuming you want a 1-D array
int valuesPresent = 0;
for (int i = 0; i < arrray.length; i++) {
for (int j = 0; i < arrray[i].length; i++) {
if (array[i][j] != "") {
valuesPresent++;
}
}
}
//Now you know how many values are there, so initialize a new array of that size
String[] answer = new String[valuesPresent];
//Now add all the values to it
int index = 0;
for (int i = 0; i < arrray.length; i++) {
for (int j = 0; i < arrray[i].length; i++) {
if (array[i][j] != "") {
answer[index] = array[i][j];
index++;
}
}
}
To get a 2-d array, easy to understand:
//Just reordered input so we can understand better
String[][] array= {{"abcd","zxcs"}, //Row 0, col 0 = abcd and col 1 = zxcs
{"asdf",""}, //Row 1, col 0 = asdf and col 1 = ""
{"",""}}; //Row 2, col 0 = "" and col 2 = ""
//Counts how many columns have values(are not equal to "") in each row
int rowsWithValues = 0; //Counts how many rows have at least 1 value. Here, 2
for (int row = 0; row < arrray.length; row++) {
for (int col = 0; col < arrray[row].length; col++) {
if (array[row][col] != "") {
rowsWithValues++; //Since there's a col with value for this row
break; //If any one value has been found, no need to check other cols
}
}
}
//Now we know how many rows we need in the result array: 2 (row 2 has no values)
String[][] result = new String[2][];
//We need to add the 2 rows with values now
int arrayIndex = 0; //Points to next empty index in result[][]
for (int row = 0; row < arrray.length; row++) {
int colsWithValues = 0; //Cols with values for each row
for (int col = 0; col < arrray[i].length; col++) {
if (array[row][col] != "") {
colsWithValues ++; //Col with value found for this row
}
}
//Eg. For row 0, colsWithValues will be 2, since 2 cols have values(abcd, zxcs)
//We need to add these 2 cols as a single array to result
String[] currentRow = new String[colsWithValues]; //Will be 2 here for row 0
int rowIndex = 0; //Points to next empty column in currentRow[]
for (int col = 0; col < array[row].length; col++) {
if (array[row][col] != "") {
currentRow[rowIndex] = array[row][col];
}
}
//After this, for row 0, currentRow will be {abcd, zxcs}
//Just add it to our result
result[arrayIndex] = currentRol;
//After 1st iteration, result will be {{"abcd", "zxcs"}, {}}
//During 2nd iteration, arrayIndex == 1, currentRow == {"asdf"}
//On adding it to result[1], result will be {{"abcd", "zxcs"}, {"asdf"}}
To start with, don't compare two Strings for equality using == or !=, even for String Arrays:
if (array[i][j] != "") {
In the case above, it should be:
if (!array[i][j].equals("")) {
If you're not quite up to Streams yet then this is one way that might interest you:
public static String[][] removeNullStringRows(String[][] array) {
if (array == null || array.length == 0) {
return null;
}
int validCount = 0; // Row Index Counter for the new 2D Array
/* Find out how may rows within the 2D array are valid
(where the do not consist of Null Strings {"", ""}).
This let's you know how many rows you need to initialize
your new 2D Array to. */
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (!array[i][j].equals("")) {
validCount++;
break;
}
}
}
/* Declare and initialize your new 2D Array. This is
assuming the column count is the same in all rows. */
String[][] array2 = new String[validCount][array[0].length];
validCount = 0; // Used as an index increment counter for the new 2D Array
// Iterate through the supplied 2D Array and weed out
// the bad (invalid) rows.
for (int i = 0; i < array.length; i++) { // Iterate Rows...
for (int j = 0; j < array[i].length; j++) { // Iterate Columns
/* Does this row contain anything other than a Null String ("")?
If it does then accept the entire Row into the new 2D Array. */
if (!array[i][j].equals("")) {
// Retrieve all the columns for this row
for (int k = 0; k < array[i].length; k++) {
array2[validCount][k] = array[i][k];
}
// The above small 'for' loop can be replaced with:
// System.arraycopy(array[i], 0, array2[validCount], 0, array[i].length);
validCount++; // Increment our Row Index Counter for the new 2D Array
break; // Get out of this column iterator. We already know it's good.
}
}
}
return array2; // Return the new 2D Array.
}
To use this method you might do it this way:
// Your current 2D Array
String[][] array = {
{"abcd",""}, {"asdf",""}, {"",""},
{"",""}, {"",""}, {"",""}
};
// If the supplied 2D Array is null contains no rows
// then get out of here.
if (array == null || array.length == 0) {
return;
}
// Display the original 2D Array (array) in the Console window
System.out.println("The original 2D Array:");
for (int i = 0; i < array.length;i++) {
System.out.println(Arrays.toString(array[i]));
}
// Remove all rows that contain all Null String Columns.
// Make your Array equal what is returned by our method.
array = removeNullStringRows(array);
// Display the new 2D Array (array) in the Console window.
System.out.println();
System.out.println("The New 2D Array:");
for (int i = 0; i < array.length;i++) {
System.out.println(Arrays.toString(array[i]));
}
And your Console Window output should look like:
The original 2D Array:
[abcd, ]
[asdf, ]
[, ]
[, ]
[, ]
[, ]
The New 2D Array:
[abcd, ]
[asdf, ]
I am assuming here that, the nested array could be of any size not just of 2 elements.
Create a predicate that takes Stream<String> and checks if any element is not null and non-empty.
String[][] array= {{"abcd",""},{"asdf",""},{"",""},{"",""},{"",""},{"",""}};
Predicate<Stream<String>> arrayPredicate = element ->
element.anyMatch(ele ->Objects.nonNull(ele) && !ele.isEmpty());
Now stream over the original array and filter the inner array based on a predicate and collect it in a new array.
String[][] copyArray = Arrays.stream(array)
.filter(arr -> arrayPredicate.test(Arrays.stream(arr)))
.toArray(String[][]::new);
array = copyArray; // reassign to array
You can filter out all null and empty elements from this 2d array as follows:
String[][] array = {{"abcd",""},{"asdf",""},{"",""},{"",""},{"",""},{"",""}};
String[][] nonEmptyArray = Arrays.stream(array)
.map(row -> Arrays.stream(row)
// filter out 'null' elements and empty strings
.filter(e -> e != null && e.length() > 0)
// an array of non-empty strings or an empty
// array if there are no such strings
.toArray(String[]::new))
// filter out empty arrays
.filter(row -> row.length > 0)
// an array of non-empty arrays
.toArray(String[][]::new);
// output
System.out.println(Arrays.deepToString(nonEmptyArray)); // [[abcd], [asdf]]
private String[][] removeFromArray(String[][] source, String[] objToRemove) {
return Arrays.stream(source)
.filter(element -> !Arrays.equals(element , objToRemove))
.toArray(String[][]::new);
}
void example() {
final String[] empty = new String[]{"", ""};
String[][] array = {{"abcd", ""}, {"asdf", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}};
array = removeFromArray(array, empty);
}
Something like that should work
I have one text file in which each String holds one line of numbers say 203 and I have one 2d array int puzzle[][].
The lines of file are in the array list Arraylist<String> lines .The first String from the array list goes into puzzle[0].The second String goes into puzzle[1], etc.
The problem I'm having is that after splitting the lines I cannot convert those numbers into integers because it gives me number format exception for -1 what if I will split that - and 1 as well.
I tried the following and also making deep copy of the string array and then transforming each string into an integer
public void parseFile(ArrayList<String> lines)
{
ArrayList<String> l = lines;
for(int i =0; i<puzzle.length; i++)
puzzle[i][0] = Integer.parseInt(l.get(i).split(""));
}
it should give me 2d array with integers
Here is a method that will take a list of strings made up of single digit numbers and convert the list to a 2d array of int. This code makes no use of Java 8 streams.
public static int[][] parseFile(List<String> lines) {
int[][] result = new int[lines.size()][];
int multiplier = 1;
int counter = 0;
for (String line : lines) {
List<Integer> row = new ArrayList<>();
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
if (c == '-') {
multiplier = -1;
continue;
}
int n = (int)c - 48;
row.add(n * multiplier);
multiplier = 1;
}
int[] rowArray = new int[row.size()];
for (int j = 0; j < row.size(); j++) {
rowArray[j] = row.get(j);
}
result[counter] = rowArray;
counter++;
}
return result;
}
Below is my test code, execute from main
List<String> list = new ArrayList<>();
list.add("-111");
list.add("2-13");
int[][] result = parseFile(list);
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[i].length; j++) {
System.out.printf("%d ", result[i][j]);
}
System.out.print("\n");
}
Output
-1 1 1
2 -1 3
I have convert a txt file into a 2d array, how can I make it look more organize?
My input file look like this:
[Name], Exam1, Exam2, Exam3
John, 99, 88, 89
May, 99, 100, 100
Mary, 100, 100, 100
Peter, 60, 60, 60
Currently I get:
[Name] Exam1 Exam2 Exam3
John 99 88 89
May 99 100 100
Mary 100 100 100
Peter 60 60 60
I want the data looks more like a table which is easier to read, how can I do that?
Code:
public static void main(String[] args) throws Exception{
File file = new File("test.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
int width = 0, height = 0;
String line = "";
/*Find number of row and column of the file.*/
while ((line = br.readLine()) != null)
{
if (width == 0)
{
/*Find the number of row using split method(",")*/
String[] str = line.split(",");
width = str.length;
}
height++;
}
System.out.println("Row : " + height);
System.out.println("Column : " + width);
/*Adding values to the 2D Array.*/
String[][] data = new String[height][width];
br = new BufferedReader(new FileReader(file));
for (int i = 0; i < height; i++)
{
if ((line = br.readLine()) != null)
{
for (int j = 0; j < width; j++)
{
String[] str = line.split(",");
data[i][j] = str[j];
System.out.print( data[i][j] + " ");
}
}
System.out.println("");
}
}
Thank you very much.
try output using printf
or you can use Formatter
I imagine your not going to want all that System.out stuff in your product but I am going to use it in an example, building on yours to show you the basic steps you will need to do.
Basically you need to make two passes over your data. First pass you should calculate the widest row of the data, so you can craft your ---- line. Then you add the like to whatever output type you are building (here it is System.out) and then walk the data again and add that to the output. You should add something like a newline or other terminator. If you want to line up the columns, you do the same thing but in the first step also record in another multi dimensional array the widest data in each column, and pad data that is shorter that the widest in each column when outputting (this will alter the width of your --- line so you will need to calculate this before building that line of course).
Here is your example modified a little bit with some of these ideas (not padding to line up the columns though, that is for you to do, it is easy trust me)
public static void main(String[] args) throws Exception {
/* Adding values to the 2D Array. */
String[][] data = { { "John", "99", "88", "89" },
{ "May", "99", "100", "100" } };
int wideRowWidth = 0;
int curRowWidth;
// WALK DATA ONCE TO FIND THE WIDEST ROW
for (int i = 0; i < data.length; i++) {
curRowWidth = 0;
for (int j = 0; j < data[i].length; j++) {
curRowWidth += data[i][j].length();
}
if (curRowWidth > wideRowWidth) {
wideRowWidth = curRowWidth;
}
}
// BUILD YOUR DASHED LINE
for (int i = 0; i < wideRowWidth + data[0].length -1; i++) {
System.out.print("-");
}
System.out.print("\n");
// USE YOUR DATA
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
System.out.print(data[i][j] + " ");
}
System.out.print("\n");
}
}
You can do it in this way, which is as follows :
// To Store and Show Values on the screen.
int columnWidth = 15;
for (int i = 0; i < height; i++)
{
if ((line = br.readLine()) != null)
{
// After reading, we are seperating them.
String[] str = line.split(", ");
for (int j = 0; j < width; j++)
{
data[i][j] = str[j];
// Here we are making the word length of each String equal,
// i.e. equal to column width. So that each String value comes
// below each other. Increase the value of columnWidth variable
// if you want to increase the width of a column or vice versa.
System.out.format("%-" + columnWidth + "s", data[i][j]);
}
}
System.out.print("\n");
}
Hope that might help.
Regards