Как создать двумерные массивы с помощью файлового ввода - PullRequest
0 голосов
/ 13 октября 2018

Мне была поставлена ​​задача выполнить матричное умножение с использованием файлового ввода.Фактическая математика для процесса умножения не проблема;это сохранение данных в двумерных массивах, что меня озадачило.

Это файл данных, который я должен использовать для создания своих двумерных массивов:

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, где я пытаюсь сохранить данные из вышеуказанного текстового файла в двумерных массивах (пытаясь сохранитьпервая матрица в массив 2d с именем "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 голосов
/ 24 февраля 2019

Я предлагаю решение без циклов 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"

0 голосов
/ 14 октября 2018

Это должно сработать (реализация с использованием статических массивов):

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 

Я уверен, что есть место для улучшений в этом алгоритме, однако он должен датьправильные результаты.

0 голосов
/ 28 октября 2018
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();
    }

}
0 голосов
/ 13 октября 2018

Я рекомендую вам использовать Java Collections вместо массивов и читать матрицу таким образом.Например, вы читаете значение «матрицы» из входного потока и вызываете этот метод:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...