Я предлагаю решение без циклов for и полной проверки ввода.вместо циклов вы можете использовать потоки Java 8 Этап проверки включает в себя: соответствие регулярных выражений, проверку размера и размеров.
The solution includes the following steps:
- Reading input matrices.
- Validating matrices.
- Converting the input into 3-d int array, with 2 cells.
(Each cell contains a 2-d int array matrix)
- Multiplying the matrices.
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.stream.IntStream;
import org.apache.commons.io.FileUtils;
/**
* This class demonstrates multiplication of 2 matrices.
* Including:
* - Reading input matrices from file.
* - Validating matrices input format (using Regex).
* - Converting input to 3-d array with 2 matrices (using streams).
* - Validating matrices sizes & dimensions.
* - multiplication of matrices (using streams).
*/
public class CreateTwo2dArraysFromATextFile {
final private static String FILE_PATH = "matrices.txt";
final private static String ENCODING = "UTF-8";
final private static String INPUT_FORMAT = "^(-?\\s*matrix\\s*(-?\\s+row(\\s+-?(\\d+))+)+){2}$";
final private static String MATRIX_TITLE = "matrix";
final private static String ROW_TITLE = "row";
final private static String MATRIX_DELIMITER = "\r\n";
final private static String ROW_DELIMITER = "\r\n";
public static void main(String[] args) throws IOException {
int[][][] matrices = fetchMatrices();
validateMatrices(matrices[0], matrices[1]);
displayMatrices(matrices);
displayMatricesMultiplicationResult(matrices[0], matrices[1]);
}
/**
* - Read 2 matrices from input file
* - Validate input format
* - Extract 2 matrices from the input file
* @return 2 matrices in 3-d int array format
* @throws IOException
*/
private static int[][][] fetchMatrices() throws IOException{
String input = FileUtils.readFileToString(new File(getFile(FILE_PATH)), ENCODING);
validateInputFormat(input);
System.out.println("Input from " + FILE_PATH);
System.out.println(input);
return getMatrices(input);
}
private static void validateMatrices(int[][] m1, int[][] m2) {
StringBuilder errors = collectInputErrors(m1, m2);
if(errors != null) {
throw new RuntimeException(errors.append("\nCannot multiply matrices, becuase the input is invalid").toString());
}
}
private static void displayMatrices(int[][][] matrices) {
System.out.println("\nMatrices in 3-d int array format:");
System.out.println(Arrays.deepToString(matrices));
}
private static void displayMatricesMultiplicationResult(int[][] m1, int[][] m2) {
System.out.println("\nMatrices Multiplication result:");
int[][] multResult = multiplyMatrices(m1, m2);
System.out.println(Arrays.deepToString(multResult));
}
private static String getFile(String fileName){
return Thread.currentThread().getContextClassLoader().getResource(fileName).getPath();
}
private static boolean isValidInput(String input) {
return input != null && input.matches(INPUT_FORMAT);
}
private static void validateInputFormat(String input) {
if(!isValidInput(input)) {
throw new RuntimeException("Invalid input format: " + input);
}
}
/**
* Attempt to detect the following validation errors:
* - The number of columns in m1 or m2 is not identical across all of the rows
* (There is at least one row with number of columns, which is different than the number of columns of all of the rows)
* - Matrices multiplication size constraints: the number of columns in m1, must be equals to the number of rows in m2.
* @param m1 first matrix
* @param m2 second matrix
* @return error messages if validation violations are detected.
* Otherwise, null will be retrieved.
*/
private static StringBuilder collectInputErrors(int[][] m1, int[][] m2) {
StringBuilder errors = new StringBuilder();
int invalidSizeRowIndex1 = getInValidSizeMatrixRowIndex(m1);
int invalidSizeRowIndex2 = getInValidSizeMatrixRowIndex(m2);
if(invalidSizeRowIndex1 != -1 || invalidSizeRowIndex2 != -1) {
errors.append("Invalid matrices size detected:");
}
if(invalidSizeRowIndex1 != -1) {
errors.append(getInvalidMatrixMessage(
"first",invalidSizeRowIndex1 + 1,
m1[invalidSizeRowIndex1].length, m1[invalidSizeRowIndex1 - 1].length));
}
if(invalidSizeRowIndex2 != -1) {
errors.append(getInvalidMatrixMessage(
"second",invalidSizeRowIndex2 + 1,
m2[invalidSizeRowIndex2].length, m2[invalidSizeRowIndex2 - 1].length));
}
int invalidDimensionRowIndex = getDimensionViolationIndex(m1, m2);
if(invalidSizeRowIndex1 == -1 && invalidSizeRowIndex2 == -1 && invalidDimensionRowIndex == -1) {
return null;
}
if(invalidDimensionRowIndex != -1 ) {
errors.append("\nInvalid matrices dimensions detected:");
errors.append(getInvalidMatrixMessage(
"first",invalidDimensionRowIndex + 1,
m1[invalidDimensionRowIndex].length, m2.length));
}
return errors;
}
private static String getInvalidMatrixMessage(String matrixTitle, int invalidRowIndex, int columnSize, int expectedColumnSize) {
return String.format("In the %s matrix, at the %d 'th row, a column with size of %d , is invalid. (expected column size is: %d)",
matrixTitle, invalidRowIndex, columnSize, expectedColumnSize);
}
/**
* Get the index of the first row in m1, that violates the matrices multiplication size constraints
* Matrix multiplication is possible iff the number of columns in m1 equals to the number of rows in m2.
* @param m1 first matrix
* @param m2 second matrix
* @return the first row index in m1 with column size
* which is different than the number of rows in m2.
* If there is no such row, then (-1) will be retrieved.
*
*/
private static int getDimensionViolationIndex(int[][] m1, int[][] m2) {
return IntStream.range(0, m1.length).filter(i -> m1[i].length != m2.length).findFirst().orElse(-1);
}
/**
* Get the index of the first row with invalid columns size (If exist)
* @param m matrix
* @return the first index of row,
* which has number of columns that is different than the previous row.
* If there is no such row, then (-1) will be retrieved.
*/
private static int getInValidSizeMatrixRowIndex(int[][] m) {
return IntStream.range(1, m.length).filter(i -> m[i].length != m[i-1].length).findFirst().orElse(-1);
}
/**
* Extract 2 matrices in 3-d int array format, using streams
* @param input
* @return 3-d int array,
* where the first cell is the first 2-d matrix
* and the second cell is the second 2-d matrix
*/
private static int[][][] getMatrices(String input) {
return Arrays.asList(input.split(MATRIX_TITLE))
.stream().filter(e -> !e.equals(""))
.map(k-> Arrays.stream(k.split(MATRIX_TITLE))
.map(r -> r.split(MATRIX_DELIMITER + ROW_TITLE))
.flatMap(r -> Arrays.stream(r))
.filter(e -> !e.equals(""))
.map(r-> Arrays.stream(r.split(ROW_DELIMITER))
.filter(e -> !e.equals(""))
.mapToInt(Integer::parseInt).toArray()
).toArray(int[][]::new)).toArray(int[][][]::new);
}
/**
* Multiply 2 matrices
* @param m1 first matrix
* @param m2 second matrix
* @return m1 X m2
*/
private static int[][] multiplyMatrices(int[][] m1, int[][] m2) {
return Arrays.stream(m1).map(r ->
IntStream.range(0, m2[0].length).map(i ->
IntStream.range(0, m2.length).map(j -> r[j] * m2[j][i]).sum()
).toArray()).toArray(int[][]::new);
}
}
Примечание: если вы хотите изменить формат ввода.например, разделители, вы можете изменить соответствующие константы:
Например, для ввода в этом формате: строка матрицы -2 0 1 3 строка -3 5 1 2 строка 0 4 3 1 строка матрицы -1 3 4 строка 04 9 строка 1 -11 5 строка 4 -5 7 использовать эту конфигурацию: MATRIX_DELIMITER = "" ROW_DELIMITER = ""
для заданного ввода - отдельные строки (как ввод, который описан в вашем примере), использовать эту конфигурацию: MATRIX_DELIMITER = "\ r \ n" ROW_DELIMITER = "\ r \ n"