Reading two matrices from one text file [closed]

会有一股神秘感。 提交于 2019-12-11 19:15:54

问题


This is a long one.

I have a very odd problem. I need to read two matrices from a text file, multiply them together, and then print out the result. That's all very easy. The problem is that the file containing the matrices looks like this:

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

How this crazy thing works is as follows (just for reference, you can skip this part):

  1. Read down the first column. Once you hit whitespace OR the end of the file you have the number of rows in your FIRST matrix.

  2. Count the number of integers per row, row-by-row. Once that count drops the you know how many rows your second matrix has. IF the first matrix was "shorter" than the file, then this step is unecessary, as the second will simply be the number of rows in the file.

  3. Since multiplication requires matrix one's column count to be the same as matrix two's row count ( [3x6 * 6x4] is valid, [3x6 * 5x4] is not) then by knowing the number of columns in matrix one we can find the number of rows in matrix two, and vice-versa.

I need to find either value.

So from that file matrix one would be

1 2
3 4
5 6
7 8

and two is

1 2 3
4 5 6

So you'd think you could just count the rows in column one and the number of columns in the last row to find everything, but sometimes the file looks like this:

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

So I just need some conditional juggling depending on whether the bottom left corner is an int or whitespace. I'm thinking reading the whole file into a 2D Array and manipulating from there.

So here are my formal questions:

I need to read in every character of the file individually, whether it be int or whitespace, so I can build a faithful Array[][]. What is the best method of doing that? I have tried Scanner, StringTokenizer, FileInputStream, BufferedInputStream, Reader, and FileReader but none of them give me a simple char by char.

Secondly, any suggestions on splitting the matrices from the unified Array[][] into two smaller Array[][]s?


回答1:


You should be able to read in the file character by character with a FileInputStream.

Please note that the read() method returns -1 at EOF. Otherwise cast the returned value to a char.




回答2:


Textfiles can only be read line by line. Therefore read a line, split it by using String.split(" ") and fill in the resulting data into a linked list which holds linked lists of Integer.Keep in mind that You have to keep track of the positions in which Your split data is in the input string to remember the start position of the second matrix in Your second case.

LinkedList<LinkedList<Integer>>

After reading all lines of the file You have the complete number of lines of the "highest" matrix and You can put the data of the first matrix in an array while dropping the same data at the same point in time from the linked list (Lisp.pop()).

  • I cannot imagine that reading into an array of arrays is possible in one run because You do not know the number of lines in advance while reading through the file. Therefore You need to use a collection class.
  • I suggest to use LinkedList because dropping wit pop is very efficient and faster than using a collection which is backed by an array.
  • LinkedList will also work for efficient multiplication of the matrix while passing through the list.



回答3:


Well it would appear that for both matrices the max number of rows is the number of lines, and max number of columns is the length of the line + 1 / 2 excluding whatever is used for the end of line (e.g. CRLF)

As you scan through the file for those two bits of info, Also look for the first or last char being a space if neither skip if the first is scan along until you bump into the second array if the last is, scan back until you bump into the first one Other possibility is of course two arrays with the same dimensions.

Armed with those bits of info , you can create the two arrays, then scan the file again and slot the values in the appropriate places.

It's a bit brutal but it will work and be easy to test.




回答4:


I suggest to split the problem in 4 phases: reading text, build an array of String cells, build an array of integer matrices, do the product of matrices:

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


来源:https://stackoverflow.com/questions/13387921/reading-two-matrices-from-one-text-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!