【问题标题】:How to create two-dimensional arrays using file input如何使用文件输入创建二维数组
【发布时间】:2019-03-18 12:40:08
【问题描述】:

我的任务是使用文件输入执行矩阵乘法。乘法过程的实际数学是没有问题的;让我困惑的是如何将数据存储到二维数组中。

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

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

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

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

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;
}

这是具有主要方法的类,我试图将上述文本文件中的数据存储到二维数组中(尝试将第一个矩阵存储到名为“a”的二维数组中,将第二个矩阵存储到名为“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;
                }
            }
        }
}

【问题讨论】:

    标签: java arrays file matrix input


    【解决方案1】:

    我建议您使用 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;
    }
    

    【讨论】:

    • 我很想使用集合并让我的代码更简单;但是,任务指定我使用二维数组。在继续讨论更复杂的主题(例如集合)之前,我宁愿掌握这个子主题。不过感谢您的建议:)
    • 你不能轻易将二维列表转换为对应的数组。我将编辑我的答案
    • 在方法末尾添加转换,查看
    • @Krish 如果您只想使用静态原始数组,您如何知道矩阵(行/列)的确切大小?因为你必须初始化它们。
    • @maspinu 就是这样——你必须使用文本文件来创建矩阵。矩阵中的每一行由“行”关键字分隔,每个矩阵由“矩阵”关键字分隔。所以你必须通过找出每行中有多少条数据来找出矩阵有多少列。
    【解决方案2】:

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

    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 
    

    我确信这个算法还有改进的空间,但是它应该会给出正确的结果。

    【讨论】:

      【解决方案3】:
      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();
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        我建议一个没有 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"

        【讨论】:

          猜你喜欢
          • 2012-11-07
          • 2022-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多