web-dev-qa-db-fra.com

Lire le fichier .text dans un tableau 2D

Il existe quelques-uns de ces sujets, mais ce problème a une légère tournure qui le rend différent. 

Je suis concentré sur la moitié d'un problème plus vaste. Je suis sûr que beaucoup d’entre vous sont conscients du problème des carrés magiques.

Invite:
Supposons un fichier avec des lignes et des nombres sur chaque ligne comme le carré indiqué. Ecrivez un programme qui lit les informations dans un tableau intS à deux dimensions. Le programme doit déterminer si la matrice est un carré magique ou non.

Solution de travail:

public static int[][] create2DIntMatrixFromFile(String filename) throws Exception {
int[][] matrix = {{1}, {2}};

File inFile = new File(filename);
Scanner in = new Scanner(inFile);

int intLength = 0;
String[] length = in.nextLine().trim().split("\\s+");
  for (int i = 0; i < length.length; i++) {
    intLength++;
  }

in.close();

matrix = new int[intLength][intLength];
in = new Scanner(inFile);

int lineCount = 0;
while (in.hasNextLine()) {
  String[] currentLine = in.nextLine().trim().split("\\s+"); 
     for (int i = 0; i < currentLine.length; i++) {
        matrix[lineCount][i] = Integer.parseInt(currentLine[i]);    
            }
  lineCount++;
 }                                 
 return matrix;
}


public static boolean isMagicSquare(int[][] square) {

  return false;
}

Voici mon (ancien) code pour lire les informations d'un fichier texte dans un tableau 2D:

public static int[][] create2DIntMatrixFromFile(String filename) throws Exception {
    int[][] matrix = {{1}, {2}};
    File inFile = new File(filename);
    Scanner in = new Scanner(inFile);
    in.useDelimiter("[/n]");

    String line = "";
    int lineCount = 0;

    while (in.hasNextLine()) {
        line = in.nextLine().trim();
        Scanner lineIn = new Scanner(line);
        lineIn.useDelimiter("");

        for (int i = 0; lineIn.hasNext(); i++) {
            matrix[lineCount][i] = Integer.parseInt(lineIn.next());
            lineIn.next();
        }

        lineCount++;
    }

    return matrix;
}

public static boolean isMagicSquare(int[][] square) {
    return false;
}

Et voici le fichier texte que je lis. Il a la forme d’un tableau 2D de 9x9, mais le programme doit prendre en charge un tableau de taille ambiguë. 

  37  48  59  70  81   2  13  24  35 
  36  38  49  60  71  73   3  14  25 
  26  28  39  50  61  72  74   4  15 
  16  27  29  40  51  62  64  75   5 
   6  17  19  30  41  52  63  65  76 
  77   7  18  20  31  42  53  55  66 
  67  78   8  10  21  32  43  54  56 
  57  68  79   9  11  22  33  44  46 
  47  58  69  80   1  12  23  34  45 

Il y a deux espaces devant chaque ligne exprès. 

Avant d’énoncer le problème exact, il s’agit d’un modèle de travail à domicile. La déclaration de la méthode et l’initialisation de la variable ont donc été prédéterminées.

Je ne suis pas sûr que la méthode crée même correctement un tableau 2D à partir du fichier car je ne peux pas l'exécuter pour le moment. Le problème est que, pour une raison quelconque, "matrice" a été initialisée avec 1 colonne et 2 lignes. Pour quelle raison je ne suis pas sûr, mais pour remplir un tableau avec les nombres du fichier, je dois créer un tableau 2D avec des dimensions égales au nombre de valeurs d'une ligne. 

J'avais précédemment écrit du code pour créer un nouveau tableau 2D 

int[line.length()][line.length()]

mais cela a créé un tableau 36x36 parce que c'est le nombre de caractères individuels sur une ligne. J'ai l'impression que c'est aussi simple que de parcourir la première ligne et de laisser un compteur garder trace de chaque séquence de nombres séparés par un zéro. 

Pour moi, cette solution semble trop inefficace et prend beaucoup de temps juste pour trouver les dimensions du nouveau tableau. Quel est le meilleur moyen d'y parvenir? Sans utiliser ArrayLists car je dois réécrire ce programme après avoir utilisé ArrayLists. 

7
BimmerM3

J'ai produit le tableau 2D suivant à partir du fichier que vous avez fourni:

 37 | 48 | 59 | 70 | 81 |  2 | 13 | 24 | 35
----+----+----+----+----+----+----+----+----
 36 | 38 | 49 | 60 | 71 | 73 |  3 | 14 | 25
----+----+----+----+----+----+----+----+----
 26 | 28 | 39 | 50 | 61 | 72 | 74 |  4 | 15
----+----+----+----+----+----+----+----+----
 16 | 27 | 29 | 40 | 51 | 62 | 64 | 75 |  5
----+----+----+----+----+----+----+----+----
  6 | 17 | 19 | 30 | 41 | 52 | 63 | 65 | 76
----+----+----+----+----+----+----+----+----
 77 |  7 | 18 | 20 | 31 | 42 | 53 | 55 | 66
----+----+----+----+----+----+----+----+----
 67 | 78 |  8 | 10 | 21 | 32 | 43 | 54 | 56
----+----+----+----+----+----+----+----+----
 57 | 68 | 79 |  9 | 11 | 22 | 33 | 44 | 46
----+----+----+----+----+----+----+----+----
 47 | 58 | 69 | 80 |  1 | 12 | 23 | 34 | 45

Le tableau détermine la taille du carré lorsqu'il lit la première ligne du fichier. C'est très dynamique. Cela fonctionne tant que le fichier d’entrée est un carré parfait. Je n'ai pas d'autre traitement d'erreur.

Voici une approche simple qui devrait adhérer à vos directives.

import Java.io.BufferedReader;
import Java.io.InputStream;
import Java.io.InputStreamReader;

public class ReadMagicSquare {
    public static int[][] create2DIntMatrixFromFile(String filename) throws Exception {
        int[][] matrix = null;

        // If included in an Eclipse project.
        InputStream stream = ClassLoader.getSystemResourceAsStream(filename);
        BufferedReader buffer = new BufferedReader(new InputStreamReader(stream));

        // If in the same directory - Probably in your case...
        // Just comment out the 2 lines above this and uncomment the line
        // that follows.
        //BufferedReader buffer = new BufferedReader(new FileReader(filename));

        String line;
        int row = 0;
        int size = 0;

        while ((line = buffer.readLine()) != null) {
            String[] vals = line.trim().split("\\s+");

            // Lazy instantiation.
            if (matrix == null) {
                size = vals.length;
                matrix = new int[size][size];
            }

            for (int col = 0; col < size; col++) {
                matrix[row][col] = Integer.parseInt(vals[col]);
            }

            row++;
        }

        return matrix;
    }

    public static void printMatrix(int[][] matrix) {
        String str = "";
        int size = matrix.length;

        if (matrix != null) {
            for (int row = 0; row < size; row++) {
                str += " ";
                for (int col = 0; col < size; col++) {
                    str += String.format("%2d",  matrix[row][col]);
                    if (col < size - 1) {
                        str += " | ";
                    }
                }
                if (row < size - 1) {
                    str += "\n";
                    for (int col = 0; col < size; col++) {
                        for (int i = 0; i < 4; i++) {
                            str += "-";
                        }
                        if (col < size - 1) {
                            str += "+";
                        }
                    }
                    str += "\n";
                } else {
                    str += "\n";
                }
            }
        }

        System.out.println(str);
    }

    public static void main(String[] args) {
        int[][] matrix = null;

        try {
            matrix = create2DIntMatrixFromFile("square.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }

        printMatrix(matrix);
    }
}

Cette approche est plus raffinée et optimisée.

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.InputStreamReader;

public class ReadMagicSquare {

    private int[][] matrix;
    private int size = -1;
    private int log10 = 0;
    private String numberFormat;

    public ReadMagicSquare(String filename) {
        try {
            readFile(filename);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void readFile(String filename) throws IOException {
        // If included in an Eclipse project.
        InputStream stream = ClassLoader.getSystemResourceAsStream(filename);
        BufferedReader buffer = new BufferedReader(new InputStreamReader(stream));

        // If in the same directory - Probably in your case...
        // Just comment out the 2 lines above this and uncomment the line
        // that follows.
        //BufferedReader buffer = new BufferedReader(new FileReader(filename));

        String line;
        int row = 0;

        while ((line = buffer.readLine()) != null) {
            String[] vals = line.trim().split("\\s+");

            // Lazy instantiation.
            if (matrix == null) {
                size = vals.length;
                matrix = new int[size][size];
                log10 = (int) Math.floor(Math.log10(size * size)) + 1;
                numberFormat = String.format("%%%dd", log10);
            }

            for (int col = 0; col < size; col++) {
                matrix[row][col] = Integer.parseInt(vals[col]);
            }

            row++;
        }
    }

    @Override
    public String toString() {
        StringBuffer buff = new StringBuffer();

        if (matrix != null) {
            for (int row = 0; row < size; row++) {
                buff.append(" ");
                for (int col = 0; col < size; col++) {
                    buff.append(String.format(numberFormat,  matrix[row][col]));
                    if (col < size - 1) {
                        buff.append(" | ");
                    }
                }
                if (row < size - 1) {
                    buff.append("\n");
                    for (int col = 0; col < size; col++) {
                        for (int i = 0; i <= log10 + 1; i++) {
                            buff.append("-");
                        }
                        if (col < size - 1) {
                            buff.append("+");
                        }
                    }
                    buff.append("\n");
                } else {
                    buff.append("\n");
                }
            }
        }

        return buff.toString();
    }

    public static void main(String[] args) {
        ReadMagicSquare square = new ReadMagicSquare("square.txt");
        System.out.println(square.toString());
    }
}
6
Mr. Polywhirl

Vous êtes proche, mais changez votre boucle while pour ressembler à ceci:

while (in.hasNextLine()) {
    Scanner lineIn = new Scanner(line);
    //The initial case - this first line is used to determine the size of the array
    if(lineIn.hasNext()) {
        //Create a String array by splitting by spaces
        String[] s = lineIn.nextLine().split(" ");
        //Reinitialize the array to hold all of your subarrays
        matrix = new int[s.length];
        for (int i = 0; i < s.length; i++) {
            //Reinitialize each subarray to hold the numbers
            matrix[i] = new int[i];
            //Finally, parse your data from the String array
            matrix[0][i] = Integer.parseInt(s[i]);
        }
    }
    //Repeat the steps now that all of your arrays have been initialized
    for (int j = 1; j < matrix.length; j++) {
        String[] s = lineIn.nextLine().split(" ");
        for (int i = 0; i < s.length; i++) {
            matrix[j][i] = Integer.parseInt(s[i]);
        }
    }
}

Le plus grand changement que vous puissiez faire pour vous faciliter la tâche consiste à obtenir vos numéros ligne par ligne. Avec chaque ligne que vous obtenez, il est facile de la diviser en un tableau de chaînes afin de pouvoir analyser chaque nombre séparément. En procédant ainsi, vous pouvez obtenir la totalité de la matrice en une fois sans avoir à avoir des compteurs gênants.

1
David Kopczyk

Avec Java 8 et c'est Streams :

  static public int[][] create2DIntMatrixFromFile(Path path) throws IOException {
    return Files.lines(path)
      .map((l)->l.trim().split("\\s+"))
      .map((sa)->Stream.of(sa).mapToInt(Integer::parseInt).toArray())
      .toArray(int[][]::new);
  }

Ceci est juste pour la partie "lecture" de la question.

0
YoYo

Commencez par tester les résultats du scanner. Je ne pense pas que ces délimiteurs fonctionneront. (En passant, la méthode nextInt() du scanner est pratique.)

Si vous pouvez supposer que l'entrée est une matrice carrée, balayer la première ligne révélera le nombre d'entiers qu'elle contient. Ensuite, vous pouvez (ré) allouer les tableaux. Traitez ensuite toutes les lignes, y compris la première que vous avez déjà analysée.

Ensuite, vous pouvez définir matrix = new int[n][n];

0
Jerry101