Чтение двух матриц из одного текстового файла

Это длинный.

У меня очень странная проблема. Мне нужно прочитать две матрицы из текстового файла, перемножить их вместе, а затем распечатать результат. Это все очень просто. Проблема в том, что файл с матрицами выглядит так:

1 2 1 2 3
3 4 4 5 6
5 6
7 8

Вот как работает эта сумасшедшая штука (просто для справки, можете пропустить эту часть):

  1. Прочитайте первую колонку. Как только вы нажмете пробел ИЛИ конец файла, у вас будет количество строк в вашей ПЕРВОЙ матрице.

  2. Подсчитайте количество целых чисел в строке, строка за строкой. Как только этот счет упадет, вы узнаете, сколько строк имеет ваша вторая матрица. ЕСЛИ первая матрица была "короче" файла, то этот шаг необязателен, так как вторая будет просто количеством строк в файле.

  3. Поскольку умножение требует, чтобы количество столбцов первой матрицы совпадало с количеством строк второй матрицы ([3x6 * 6x4] допустимо, [3x6 * 5x4] — нет), то, зная количество столбцов в матрице один, мы можем найти количество строк в матрице два и наоборот.

Мне нужно найти любое значение.

Таким образом, из этой файловой матрицы можно было бы

1 2
3 4
5 6
7 8

и два

1 2 3
4 5 6

Таким образом, вы можете подумать, что можете просто подсчитать количество строк в первом столбце и количество столбцов в последней строке, чтобы найти все, но иногда файл выглядит так:

1 2 1 2 3
3 4 4 5 6
      7 8

Поэтому мне просто нужно некоторое условное жонглирование в зависимости от того, является ли нижний левый угол целым или пробелом. Я думаю, что читаю весь файл в 2D-массив и манипулирую оттуда.

Итак, вот мои формальные вопросы:

Мне нужно прочитать каждый символ файла по отдельности, будь то int или пробел, чтобы я мог построить верный массив[][]. Каков наилучший способ сделать это? Я пробовал Scanner, StringTokenizer, FileInputStream, BufferedInputStream, Reader и FileReader, но ни один из них не дает мне простой символ за символом.

Во-вторых, какие-либо предложения по разделению матриц из единого массива [][] на два меньших массива [][]?


person Andrew Seitz    schedule 14.11.2012    source источник
comment
Откуда берутся эти текстовые файлы?   -  person Thorbjørn Ravn Andersen    schedule 15.11.2012
comment
Они взяты из теста JUnit, поэтому они неизменны.   -  person Andrew Seitz    schedule 15.11.2012
comment
@ ThorbjørnRavnAndersen Я полагаю, что если бы мы предоставили наиболее вероятный ответ на ваш вопрос, модераторы вмешались бы.   -  person Tony Hopkinson    schedule 15.11.2012
comment
@TonyHopkinson Я не понимаю твоей точки зрения. Если вы шутите, то учтите, что я не носитель языка.   -  person Thorbjørn Ravn Andersen    schedule 15.11.2012
comment
Члены всегда однозначные?   -  person Tony Hopkinson    schedule 15.11.2012
comment
Да, каждый однозначный.   -  person Andrew Seitz    schedule 15.11.2012
comment
Что значит шутить? :) Я предполагал, что, возможно, этот вывод был не лучшим выбором для дальнейшей обработки.   -  person Tony Hopkinson    schedule 15.11.2012
comment
Мы с Торбьорном, вероятно, думали, что лучшее решение — заставить глупого пользователя использовать логический формат. Но, к сожалению, в данном случае это явно невозможно =(   -  person Andrew Seitz    schedule 15.11.2012


Ответы (4)


Вы должны иметь возможность читать файл посимвольно с помощью FileInputStream.

Обратите внимание, что метод read() возвращает -1 в конце EOF. В противном случае приведите возвращаемое значение к символу.

person Thorbjørn Ravn Andersen    schedule 14.11.2012
comment
Если я создаю FileInputStream для файла и использую (char) FileIn.read(), я все равно получаю байтовое значение символов. 1 2 1 2 3 становится 49,32,49,32,50 (или любым другим). Что двойное нечетное, потому что это не символы ... Вы это имели в виду? - person Andrew Seitz; 15.11.2012
comment
О, смотри, я делал это совершенно неправильно. Это оно. Теперь я могу прочитать каждый символ. - person Andrew Seitz; 15.11.2012

Текстовые файлы можно читать только построчно. Поэтому прочитайте строку, разделите ее с помощью String.split(" ") и заполните полученные данные в связанный список, который содержит связанные списки целых чисел. Имейте в виду, что вы должны отслеживать позиции, в которых ваши разделенные данные находится во входной строке, чтобы запомнить начальную позицию второй матрицы в Вашем втором случае.

LinkedList<LinkedList<Integer>>

После прочтения всех строк файла у вас есть полное количество строк «самой высокой» матрицы, и вы можете поместить данные первой матрицы в массив, удаляя те же данные в тот же момент времени из связанного списка (Lisp .поп()).

  • Я не могу представить, что чтение в массив массивов возможно за один прогон, т.к. Вы не знаете заранее количество строк при чтении файла. Поэтому вам нужно использовать класс коллекции.
  • Я предлагаю использовать LinkedList, потому что удаление остроумия очень эффективно и быстрее, чем использование коллекции, которая поддерживается массивом.
  • LinkedList также будет работать для эффективного умножения матрицы при прохождении по списку.
person E.S.    schedule 14.11.2012
comment
К сожалению, я не могу использовать какой-либо метод разделителя, потому что некоторые пробелы, которые он пропустит, важны. Я использовал обычные массивы, потому что к этому моменту я БУДУ знать размеры файла, и после того, как я вмешиваюсь в этот массив [][], я могу легко определить размеры двух матриц. - person Andrew Seitz; 15.11.2012

Что ж, может показаться, что для обеих матриц максимальное количество строк — это количество строк, а максимальное количество столбцов — это длина строки + 1/2, исключая все, что используется для конца строки (например, CRLF)

Когда вы сканируете файл в поисках этих двух битов информации, также ищите первый или последний символ, являющийся пробелом, если ни один из них не пропускается, если первый сканируется до тех пор, пока вы не наткнетесь на второй массив, если последний, сканируйте назад, пока не наткнетесь в первый Другая возможность - это, конечно, два массива с одинаковыми размерами.

Вооружившись этими битами информации, вы можете создать два массива, затем снова просмотреть файл и разместить значения в соответствующих местах.

Это немного жестоко, но это будет работать и его легко проверить.

person Tony Hopkinson    schedule 14.11.2012
comment
Я думал о чем-то подобном. Если вы сканируете крайний правый столбец, то количество строк равно количеству строк во второй матрице И количеству столбцов в первой. Затем, если вы вычтете это число из ширины файла, вы найдете количество столбцов в матрице 2. Затем вы можете просто отсканировать количество строк в первом столбце для строк в матрице 1. тогда у меня есть все данные, которые мне нужны . Мне просто нужен самый простой способ сделать это. - person Andrew Seitz; 15.11.2012
comment
Если бы это был я, я бы просто читал каждую строку, один проход, чтобы разобрать файл, другой, чтобы выкопать из него числа. Если не было какого-то большого большого файла большого количества из них, не вижу смысла слишком умничать в отношении простого / элегантного маршрута. Заставьте это работать, тогда, если у вас есть какое-то оправдание для поиска самого умного способа, по крайней мере, у вас есть что-то, с чем его можно сравнить. - person Tony Hopkinson; 15.11.2012

Предлагаю разбить задачу на 4 этапа: чтение текста, построение массива строковых ячеек, построение массива целочисленных матриц, произведение матриц:

import java.util.ArrayList;
import java.util.List;

public class MatrixMul {
   static String[][] text2StrMatrices( String[] text ) {
      List< String[] > w = new ArrayList<>( 12 );
      for( String line : text )
      {
         List< String > l = new ArrayList<>( line.length() / 2 );
         for( int i = 0; i < line.length(); ++i )
         {
            char c = line.charAt( i );
            if( c == ' ' )
            {
               l.add( " " );
               ++i;
            }
            else {
               String num = "";
               while( c != ' ' && i < line.length()) {
                  num += c;
                  if( ++i < line.length()) {
                     c = line.charAt( i );
                  }
               }
               l.add( num );
            }
         }
         w.add( l.toArray( new String[l.size()]));
      }
      return w.toArray( new String[w.size()][] );
   }

   static int countValues( String[] row )
   {
      int count = 0;
      for( String value : row ) {
         if( value.trim().length() > 0 ) {
            ++count;
         }
      }
      return count;
   }

   static int[][][] strMatrices2IntegerMatrices( String[][] str ) {
      int count = str[0].length;
      int row = 0;
      while( row < str.length && count == countValues( str[row] )) {
         ++row;
      }
      int first = -1;
      for( int i = 0; first == -1 && i < str[row].length; ++i ) {
         if( str[row][i].trim().length() > 0 ) {
            first = i;
         }
      }
      int columns = 0;
      if( first > 0 ) {
         columns = first;
      }
      else {
         columns = countValues( str[row] );
      }
      List<int[]> w = new ArrayList<>(4);
      for( int r = 0; r < ( first == 0 ? str.length : row ); ++r )
      {
         int[] aRow = new int[columns];
         for( int c = 0; c < columns; ++c ) {
            aRow[c] = Integer.parseInt( str[r][c] );
         }
         w.add( aRow );
      }
      int[][][] result = new int[2][][];
      result[0] = w.toArray( new int[w.size()][] );
      w.clear();
      for( int r = 0; r < ( first == 0 ? row : str.length ); ++r )
      {
         int[] aRow = new int[str[0].length-columns];
         for( int c = columns; c < str[r].length; ++c ) {
            aRow[c-columns] = Integer.parseInt( str[r][c] );
         }
         w.add( aRow );
      }
      result[1] = w.toArray( new int[w.size()][] );
      return result;
   }

   private static int[][] matricesProduct( int[][] a, int[][] b )
   {
      int m = a.length;
      int n = b[0].length;
      int p = b.length;
      assert ( m == n ) || ( a[0].length == p ): "Incompatible dimensions";
      int[][] prod = null;
      if( p > -1 ) {
         prod = new int[m][n];
         for( int i = 0; i < m; ++i ) {
            for( int j = 0; j < n; ++j ) {
               for( int k = 0; k < p; ++k ) {
                  prod[i][j] += a[i][k] * b[k][j];
               }
            }
         }
      }
      return prod;
   }

   static void test(
      String     title,
      String[]   text,
      String[][] expectedStrMatrices,
      int[][][]  expectedMatrices,
      int[][]    expectedProduct )
   {
      System.out.println( title );
      final String[][] observedStrMatrices = text2StrMatrices( text );
      assert compare( expectedStrMatrices, observedStrMatrices ):
         "text2StrMatrices() failed";
      final int[][][] observedMatrices =
         strMatrices2IntegerMatrices( observedStrMatrices );
      assert compare( expectedMatrices, observedMatrices ):
         "strMatrices2IntegerMatrices() failed";
      final int[][] observedProduct =
         matricesProduct( observedMatrices[0], observedMatrices[1] );
      displayMatrix( observedProduct );
      assert compare( expectedProduct, observedProduct ):
         "matricesProduct() failed";
   }

   public static void main( String[] args ) {
      final String[] text1 = {
         "1 2 1 2 3",
         "3 4 4 5 6",
         "5 6",
         "7 8",
      };
      final String[][] expectedStrMatrices1 = {
         { "1", "2", "1", "2", "3" },
         { "3", "4", "4", "5", "6" },
         { "5", "6" },
         { "7", "8" },
      };
      final int[][][] expectedMatrices1 = {{
            { 1, 2 },
            { 3, 4 },
            { 5, 6 },
            { 7, 8 },
         },{
            { 1, 2, 3 },
            { 4, 5, 6 },
         }};
      final int[][] expectedProduct1 = {
         {  9, 12, 15 },
         { 19, 26, 33 },
         { 29, 40, 51 },
         { 39, 54, 69 },
      };
      test( "First test case", text1, expectedStrMatrices1, expectedMatrices1, expectedProduct1 );
      final String[] text2 = {
         "1 2 1 2 3",
         "3 4 4 5 6",
         "      7 8",
      };
      final String[][] expectedStrMatrices2 = {
         { "1", "2", "1", "2", "3" },
         { "3", "4", "4", "5", "6" },
         { " ", " ", " ", "7", "8" },
      };
      final int[][][] expectedMatrices2 = {{
            { 1, 2, 1 },
            { 3, 4, 4 },
         },{
            { 2, 3 },
            { 5, 6 },
            { 7, 8 },
         }};
      final int[][] expectedProduct2 = {
         { 19, 23 },
         { 54, 65 },
      };
      test( "Second test case", text2, expectedStrMatrices2, expectedMatrices2, expectedProduct2 );
   }// void main( String[] args )

   private static void displayMatrix( int[][] matrix ) {
      for( int i = 0; i < matrix.length; ++i ) {
         for( int j = 0; j < matrix[i].length; ++j ) {
            System.out.printf( "%2d ", matrix[i][j] );
         }
         System.out.println();
      }

   }

   static boolean compare( String[][] left, String[][] right ) {
      if( left.length != right.length ) {
         return false;
      }
      for( int i = 0; i < left.length; ++i ) {
         if( left[i].length != right[i].length ) {
            return false;
         }
         for( int j = 0; j < left[i].length; ++j ) {
            if( ! left[i][j].equals( right[i][j] )) {
               return false;
            }
         }
      }
      return true;
   }

   static boolean compare( int[][][] left, int[][][] right ) {
      if( left.length != right.length ) {
         return false;
      }
      for( int i = 0; i < left.length; ++i ) {
         if( left[i].length != right[i].length ) {
            return false;
         }
         for( int j = 0; j < left[i].length; ++j ) {
            if( left[i][j].length != right[i][j].length ) {
               return false;
            }
            for( int k = 0; k < left[i][j].length; ++k ) {
               if( left[i][j][k] != right[i][j][k] ) {
                  return false;
               }
            }
         }
      }
      return true;
   }

   private static boolean compare( int[][] left, int[][] right )
   {
      if( left.length != right.length ) {
         return false;
      }
      for( int i = 0; i < left.length; ++i ) {
         if( left[i].length != right[i].length ) {
            return false;
         }
         for( int j = 0; j < left[i].length; ++j ) {
            if( left[i][j] != right[i][j] ) {
               return false;
            }
         }
      }
      return true;
   }
}
person Aubin    schedule 14.11.2012
comment
Спасибо за ваши усилия, это помогло мне заставить мою фазу чтения работать. - person Andrew Seitz; 15.11.2012