如何使用文件输入创建二维数组

时间:2018-10-13 14:10:58

标签: java arrays file matrix input

我被安排使用文件输入执行矩阵乘法的任务。乘法过程的实际数学运算没有问题;将数据存储到二维数组中使我感到困惑。

这是我用来创建二维数组的数据文件:

matrix
row
1
2
-2
0
row
-3
4
7
2
row
6
0
3
1
matrix
row
-1
3
row
0
9
row
1
-11
row
4
-5

规则很简单:新矩阵的开始将以“矩阵”表示,新行的开始将以“行”表示,后跟分配给该行每一列的数字。

对于上下文,这是我的矩阵乘法方法:

static int[][] mult(int[][] a, int[][] b) {

    int aRow = a.length;
    int aCol = a[0].length;

    int bRow = b.length;
    int bCol = b[0].length;

    if (bRow != aCol) {
        throw new IllegalArgumentException("Matrix A is not multipliable by Matrix B");
    }

    int[][] product = new int[aRow][bCol];

    for (int i = 0; i < product.length; i++) {
        for (int j = 0; j < product[i].length; j++) {
            for (int k = 0; k < aCol; k++) {
                product[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    return product;
}

这是具有main方法的类,在该类中,我尝试将上述文本文件中的数据存储到二维数组中(尝试将第一个矩阵存储到名为“ a”的2d数组中,将第二个矩阵存储到名为“ b”的二维数组):

public static void main(String[] args) throws FileNotFoundException {

    Scanner scanner = new Scanner(new File("/Users/Krish/IdeaProjects/Lessons/src/Lesson34/MatrixData.txt"));
    String text[] = new String[100];
    int index = -1;

    while (scanner.hasNext()) {
        text[++index] = scanner.nextLine();
    }


    int[][] a = {{}};
    int[][] b = {{}};
    int[][] product = MatrixMult.mult(a, b);

    for (int i = 0; i < product.length; i++) {
        for (int j = 0; j < product[i].length; j++) {
            System.out.print(product[i][j] + "\t");
        }
        System.out.println();
    }

    scanner.close();

}

我知道我必须执行以下操作,但是说实话,我不知道如何做,并且非常感谢您的帮助/指导:

for (int i = 0; i <= index; i++) {

        Scanner line = new Scanner(text[i]);
        int n = 0;

        while (line.hasNextInt()) {
            n = line.nextInt();
            for (int j = 0; j < a.length; j++) {
                for (int k = 0; k < a[j].length; k++) {
                    a[j][k] = n;
                }
            }
        }
}

4 个答案:

答案 0 :(得分:2)

我建议您使用Java集合而不是数组,并以这种方式读取矩阵。 例如,您从输入流中读取“矩阵”值并调用此方法:

private int[][] readMatrix(final BufferedReader reader) {
    List<List<Integer>> matrix = new ArrayList<>();
    int rowNumber = -1;
    while(reader.hasNext()) {
        String value = reader.readLine();
        if ("row".equals(value)) {
            ++rowNumber;
            matrix.add(new ArrayList<Integer>());
        } else {
            int intValue = Integer.parseInt(value);
            matrix.get(rowNumber).add(intValue);
        }
    }

    // convert to an array
    int[][] array = new int[matrix.size()][];
    for (int i = 0; i < matrix.size(); ++i) {
        List<Integer> row = matrix.get(i);
        array[i] = row.toArray(new int[row.size()]);
    }
    return array;
}

答案 1 :(得分:0)

这应该可以解决问题(使用静态数组实现):

public class Main {
    private static final String MATRIX_WORD = "matrix";
    private static final String ROW_WORD = "row";

    public static void main(String[] args) throws FileNotFoundException {
        int[][][] allMatrix = getAllMatrix(args[0]);

        for (int[][] currentMatrix : allMatrix) {
            for (int i = 0 ; i < currentMatrix.length; i++) {
                for (int j = 0; j < currentMatrix[i].length; j++) {
                    System.out.print(currentMatrix[i][j] + " ");
                }
                System.out.println();
            }
            System.out.println("\n\n");
        }
    }

    private static int[][][] getAllMatrix(String fileName) throws FileNotFoundException {
        int[][][] allMatrix = new int[0][0][0];
        int[][] currentMatrix = new int[0][0];
        String line;

        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
            while ((line = br.readLine()) != null) {

                switch (line) {
                    case MATRIX_WORD:
                        allMatrix = Arrays.copyOf(allMatrix, allMatrix.length + 1);
                        allMatrix[allMatrix.length - 1] = currentMatrix;
                        currentMatrix = new int[0][0];
                        break;
                    case ROW_WORD:
                        currentMatrix = Arrays.copyOf(currentMatrix, currentMatrix.length + 1);
                        currentMatrix[currentMatrix.length - 1] = new int[0];
                        break;
                    default:
                        currentMatrix[currentMatrix.length - 1] = Arrays.copyOf(currentMatrix[currentMatrix.length - 1],
                                currentMatrix[currentMatrix.length - 1].length + 1);
                        currentMatrix[currentMatrix.length - 1][currentMatrix[currentMatrix.length - 1].length - 1] = Integer.parseInt(line);
                        break;
                }
            }

            allMatrix = Arrays.copyOf(allMatrix, allMatrix.length + 1);
            allMatrix[allMatrix.length - 1] = currentMatrix;

        } catch (IOException e) {
            e.printStackTrace();
        }

        return allMatrix;
    }
}

我使用Arrays.copyof()扩展了当前数组(让它为元素留出更多空间)。

对于您的输入文件,输出为:

1 2 -2 0 
-3 4 7 2 
6 0 3 1 


-1 3 
0 9 
1 -11 
4 -5 

我确定该算法仍有改进的空间,但是应该给出正确的结果。

答案 2 :(得分:0)

public static void main(String[] args) throws FileNotFoundException {

    /*
     * -3   43
     * 18   -60
     * 1    -20
     */

    Scanner scanner = new Scanner(new File("/Users/Krish/IdeaProjects/Lessons/src/Lesson34/MatrixData"));
    String[] text = new String[100];
    int index = -1;

    while (scanner.hasNext()) {
        text[++index] = scanner.nextLine();
    }

    scanner.close();

    int matrixCount = 0;
    int rowCount = 0, colCount = 0;
    int aRows = 0, aCols = 0;
    int bRows, bCols;

    for (int i = 0; i <= index; i++) {
        switch (text[i]) {
            case "matrix":
                if (++matrixCount == 2) {
                    aRows = rowCount;
                    aCols = colCount;
                }
                rowCount = 0;
                colCount = 0;
                break;
            case "row":
                rowCount++;
                colCount = 0;
                break;
            default:
                colCount++;
                break;
        }
    }

    bRows = rowCount;
    bCols = colCount;

    int[][] a = new int[aRows][aCols];
    int[][] b = new int[bRows][bCols];

    matrixCount = 0;
    int rowIndex = -1, colIndex = -1;

    for (int i = 0; i <= index; i++) {
        switch (text[i]) {
            case "matrix":
                matrixCount++;
                rowIndex = -1;
                colIndex = -1;
                break;
            case "row":
                rowIndex++;
                colIndex = -1;
                break;
            default:
                colIndex++;
                if (matrixCount == 1) {
                    a[rowIndex][colIndex] = Integer.parseInt(text[i]);
                } else {
                    b[rowIndex][colIndex] = Integer.parseInt(text[i]);
                }
                break;
        }
    }

    int[][] product = MatrixMult.mult(a, b);

    for (int i = 0; i < product.length; i++) {
        for (int j = 0; j < product[i].length; j++) {
            System.out.print(product[i][j] + "\t");
        }
        System.out.println();
    }

}

答案 3 :(得分:0)

我建议不使用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行0 4 9行1 -11 5行4 -5 7 使用此配置: MATRIX_DELIMITER =“” ROW_DELIMITER =“”

对于给定的输入,

是分隔的行(例如您的示例中描述的输入) 使用此配置: MATRIX_DELIMITER =“ \ r \ n” ROW_DELIMITER =“ \ r \ n”

相关问题