Input/Output CSV Parser list unvollständig

Deiuta

Mitglied
Hallo ihr,

bin neu hier und blutige Java-Anfängerin.

Trotzdem arbeite ich an einem umfangreichen Projekt und muss unter Anderem CVS-Dateien mit vielen Datensätzen einlesen können. Dazu habe ich folgenden Code gefunden und ihn nach meinen Bedürfnissen abgeändert :

Java:
package Import;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.swing.JFileChooser;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

public class CSVParser {
   
   
    public static String fileChose() {

        JFileChooser fc = new JFileChooser();

        int ret = fc.showOpenDialog(null);

        if (ret == JFileChooser.APPROVE_OPTION) {

            File file = fc.getSelectedFile();

            String filename = file.getAbsolutePath();

            return filename;

        } else {

            return null;
        }
    }

    public static TableModel parse(File f) throws FileNotFoundException {

        ArrayList<String> headers = new ArrayList<String>();
        ArrayList<String> oneDdata = new ArrayList<String>();
        @SuppressWarnings("resource")
        Scanner lineScan = new Scanner(f);
        @SuppressWarnings("resource")
        Scanner s = new Scanner(lineScan.nextLine());
        s.useDelimiter(",");

        while (s.hasNext()) {

            headers.add(s.next());

        }
        while (lineScan.hasNextLine()) {

            s = new Scanner(lineScan.nextLine());
            s.useDelimiter(",");
            while (s.hasNext()) {
                oneDdata.add(s.next());
            }
        }
        String[][] data = new String[headers.size()][oneDdata.size()/headers.size()];

        for (int x = 0; x < headers.size(); x++) {
            for (int y = 0; y < data[0].length ; y++) {
                data[x][y] = oneDdata.remove(0);
            }
        }

        return new DefaultTableModel(data, headers.toArray());
    }

    public static void main(String[] args) throws FileNotFoundException {

        TableModel t = CSVParser.parse(new File(fileChose()));

        for (int x = 0; x < t.getColumnCount(); x++) {
            System.out.print(t.getColumnName(x) + " ");
        }
        System.out.println(); // Print all the data from the table.
        for (int x = 0; x < t.getRowCount(); x++) {
            for (int y = 0; y < t.getColumnCount(); y++) {
                System.out.print(t.getValueAt(x, y) + " ");
            }
            System.out.println();
        }
    }
   
   
}

Leider wird lediglich die Header-Zeile, sowie die erste Zeile danach ausgegeben. Mehr nicht. Woran kann das liegen? Sehe den Fehler einfach nicht 🙁

Kann mir bitte jemand helfen?
 
Der Code der String[][] data erzeugt ist nicht korrekt. Dort sind Zeilen und Spalten irgendwie vertauscht worden. Versuche es mal so:
Java:
    final int rowCount = oneDdata.size() / headers.size();
    final int columnCount = headers.size();
    String[][] data = new String[rowCount][columnCount];
    for ( int x = 0; x < rowCount; x++ ) {
      for ( int y = 0; y < columnCount; y++ ) {
        data[x][y] = oneDdata.remove( 0 );
      }
    }
 
Hallo und Entschuldigung für die verspätete Antwort, hatte viel zu tun in den letzten Tagen.

Funktioniert schon viel besser, vielen Dank dafür!

Leider entspricht der Input noch nicht ganz dem Output nach dem Einlesen. Die Test-CSV sollte so aussehen:

Input.png

(Habe diese zu Testzwecken so ,,verunstaltet")

Der Output ist:

Output.png

- Kommazahlen werden auf Grund der delimiter-Definition als Abtrennungszeichen interpretiert --> setzt man den demilimiter auf ";", so kommt eine Fehlermeldung:

Fehlermeldung.png

Edit: Bei der Meldung steht noch eine IndexOutOfBoundsException

Wie schaffe ich es hier den richtigen, einheitlichen Output zu erzeugen?

Nehmt mich bitte nicht auseinander, wenn die Antwort für euch offensichtlich ist, ich bin noch Anfängerin 🙂
 
Es nimmt dich keiner auseinander, aber ich weiss ja nicht wie dein aktueller Code aussieht. Ich habe mal mit diesem Stand das ganze getestet und es funktioniert:

Java:
    public static TableModel parse(File f) throws FileNotFoundException {

        ArrayList<String> headers = new ArrayList<String>();
        ArrayList<String> oneDdata = new ArrayList<String>();
        @SuppressWarnings("resource")
        Scanner lineScan = new Scanner(f);
        @SuppressWarnings("resource")
        Scanner s = new Scanner(lineScan.nextLine());
        s.useDelimiter("; ");

        while (s.hasNext()) {
            headers.add(s.next());
        }
        while (lineScan.hasNextLine()) {
            s = new Scanner(lineScan.nextLine());
            s.useDelimiter("; ");
            while (s.hasNext()) {
                oneDdata.add(s.next());
            }
        }
        final int rowCount = oneDdata.size() / headers.size();
        final int columnCount = headers.size();
        String[][] data = new String[rowCount][columnCount];
        for (int x = 0; x < rowCount; x++) {
            for (int y = 0; y < columnCount; y++) {
                data[x][y] = oneDdata.remove(0);
            }
        }

        return new DefaultTableModel(data, headers.toArray());
    }

Wo genau hatte er denn bei dir die Exception geworfen ?

Edit: mein Output sieht bei einer entsprechenden Eingabedatei so aus:

Adam Eva Kain Abel
1,1 2 3 4
5 6 7 8

diese 1,1 war eben der erste Eintrag in dieser Zeile. Die anderen sind "gewöhnliche" integers

Nochmal Edit: wenn man allerdings leere Einträge im Header hat dann stimmt dein rowCount nicht mehr und im folgenden geht es dann durcheinander. Das liegt aber nicht am Delimiter !!!
 
Zuletzt bearbeitet von einem Moderator:
Wie JStein schon sagte sind die leeren Einträge im Header ein Problem.
Ein weiteres Problem sind Zeilen unterschiedlicher Länge, da du in deinem Algorithmus alle Zellen zeilenübergreifend in eine einzige Liste einfügst. Dort sind dann natürlich keine Informationen mehr über die Zeilenlängen vorhanden. Du müsstest hier mit einer Liste von Listen arbeiten, etwa so:
Java:
    final List<List<String>> rows = new ArrayList<>();
    while ( lineScan.hasNextLine() ) {
       s = new Scanner( lineScan.nextLine() );
       s.useDelimiter( "," );
       List<String> row = new ArrayList<String>();
       while ( s.hasNext() ) {
         row.add( s.next() );
       }
       rows.add( row );
     }
Die Erzeugung von data bzw. des TableModels muss dann entsprechend angepasst werden.
 
Und zwar die leeren Einträge am Ende einer Eingabezeile !! Nur der Vollständigkeit halber 🙂🙂
Der Scanner liefert in so einem Fall dann auch nur drei Einträge. Bzw. halt einen weniger als der columnCount eigentlich sein sollte. (Entsprechend bei den Daten-Zeilen.)
 
Zuletzt bearbeitet:
Vielen lieben Dank für die hilfreichen Tipps, ich werde es gleich morgen mal ausprobieren und euch ein Feedback geben.

Da hab ich mir ja was angetan... 😕
 
Hallo,

das Ganze läuft jetzt einigermaßen.

Allerdings muss ich mit den einzelnen Werten verschiedener Spalten Berechnungen durchführen.

Kann mir jemand bitte kurz erklären, wie ich zB. den ersten Wert aus der ersten Spalte mit dem ersten Wert der zweiten Spalte addiere??? Damit ich ein Gefühl dafür bekomme, wie man auf die verschiedenen Elemente zugreift.

Vielen Dank schonmal!
 
Sage uns doch bitte noch wie du es gelöst hast ? So wie von Enceladus vorgeschlagen ?

Edit: und wenn du weisst dass es funktioniert dann solltest du doch auch wissen wie du auf die Werte zugreifst, du hast sie dir doch sicher testweise ausgeben lassen ?
 
Habe jetzt folgenden Code:

Java:
public static TableModel parse(File f) throws FileNotFoundException {

        ArrayList<String> headers = new ArrayList<String>();
        ArrayList<String> oneDdata = new ArrayList<String>();
        @SuppressWarnings("resource")
        Scanner lineScan = new Scanner(f);
        @SuppressWarnings("resource")
        Scanner s = new Scanner(lineScan.nextLine());
        s.useDelimiter(";");

        while (s.hasNext()) {

            headers.add(s.next().trim());

        }
        while (lineScan.hasNextLine()) {

            s = new Scanner(lineScan.nextLine());
            s.useDelimiter(";");  //der Delimiter war falsch gesetzt, so dass die Tabelle falsch ausgegeben wurde
            while (s.hasNext()) {
                oneDdata.add(s.next().trim());  //hier hatten sich whitespaces versteckt
            }
        }
       
        final int rowCount = oneDdata.size()/ headers.size(); //Danke an Enceladus
        final int columnCount = headers.size();
        String[][] data = new String[rowCount][columnCount];
        for (int x = 0; x < rowCount; x++) {
            for (int y = 0; y < columnCount; y++) {
                data[x][y] = oneDdata.remove(0);
            }
        }

        return new DefaultTableModel(data, headers.toArray());
    }

    public static void main(String[] args) throws FileNotFoundException {

        TableModel t = CSVParser.parse(new File(fileChose()));

        for (int x = 0; x < t.getColumnCount(); x++) {
            System.out.print(t.getColumnName(x) + "|"); // das "|" ist zu Übersichtlichkeitszwecken
        }
        System.out.println();
        for (int x = 0; x < t.getRowCount(); x++) {
            for (int y = 0; y < t.getColumnCount(); y++) {
                System.out.print(t.getValueAt(x, y) + "|");
            }
            System.out.println();
        }
    }

}

Es lag hauptsächlich am Delimiter. Das einzige Problem ist nun noch Folgendes:

- kleine Tabelle mit 4 Spalten plus Inhalt --> Ausgabe wie gewünscht
- Tabelle mit 78 Spalten (das ist der eigentliche Umfang, den ich brauche) --> Ausgabe der Zeilen/Spalteninhalte wie gewünscht ABER: ab der zweiten Inhaltszeile (nicht Überschriften) hängt der mir den jewiligen Inhalt der ersten Spalte ans Ende der jeweiligen Zeile. D.h. das erste Element der jeweiligen Zeile, steht plptzlich am Ende. Hoffe das ist verständlich.

Leider sind die Daten der Tabellen vertraulich, sonst würde ich euch ein Beispiel posten.

Ich versteh das einfach nicht.....
 
Ich habe mir deinen Code genommen und eine Eingabedatei mit 78 Spalten gebastelt und es funktioniert !!!
Kann es sein dass es wieder ein Seiteneffekt bei deinen Eingabedaten ist ??
 
Hallo JStein52,

du hast Recht! Habe es gerade auch nochmals mit einer Test-CSV diesen Umfanges versucht und es funktioniert tatsächlich! Es liegt also wirklich an den Eingabedaten. Nun muss ich nurnoch darauf kommen, was an denen anders ist und zu dieser Ausgabe führt.

Könntest du, oder jemand Anderes mit vielleicht zeigen, wie ich nun Berechnungen mit Werten aus verschiedenen Spalten durchführen kann? Kann ja schlecht jeden Wert/jede Spalte manuell in eine Variable speichern, oder?

Vielen Dank schonmal!

Habe übrigens durch Eure Hilfe schon sehr viel dazu gelernt.

EDIT: kann ich das über den Zugriff auf dieses Array machen? Wenn ja, wie?
Java:
...
String[][] data = new String[rowCount][columnCount];
        for (int x = 0; x < rowCount; x++) {
            for (int y = 0; y < columnCount; y++) {
                data[x][y] = oneDdata.remove(0);
            }
...
 
Zuletzt bearbeitet von einem Moderator:
Ja, du kannst dir z.B. aus diesem String-Array eine double-Array machen etwa so:

Code:
double[][] dblData = new double[rowCount][columnCount];
        for (int x = 0; x < rowCount; x++) {
            for (int y = 0; y < columnCount; y++) {
                dblData[x][y] = Double.parseDouble(oneDdata.remove(0));

oder du wandelst immer an den Stellen wo du damit rechenen willst die einzelnen Operanden von String nach double um, z.B.
Code:
double ergebnis = Double.parseDouble(data[x][y]) + Double.parseDouble(data[x][y+1]);
 
Zu früh gefreut...

angenommen ich möchte die Werte in einer anderen Klasse ,,Statistics" aufrufen (nach Deiner Methode) und daraus bsplw. den Durchschnitt berechnen, etwa so:

Java:
public static double mean(ArrayList<Double> val){
       
       

             double sum = 0;
            
             for (double d : val)
                 sum += d;

             return sum/val.size();
        }

...wie müsste ich das anstellen?

Bin völlig überfordert
 
🙂 Ok, kriegen wir schon. Du machst dir z.B. in der Klasse CVSParser eine (oder mehrere ) Getter-Methode die dir
die gewünschten Daten (z.B. alle Werte einer bestimmten Spalte oder je nach dem was du brauchst) als List<Double>
zurückliefert. In dieser Getter-Methode wandelst du deine Strings so wie oben beschrieben in double-Werte um. Wäre das eine Idee ?
 
Hallo, ich wieder 🙂
Leider finde ich im Internet nichts passendes dazu, daher hier ein neues Problem:

Wie kann ich es umsetzen, dass erkannt wird, wenn eine Zeile (Datensatz) einen gewissen String (zB "ABC") enthält und diesen Datensatz daraufhin beim Einlesen auslässt?

Danke 🙂
 
Dort wo du den String einliest fragst du ab ob der String etwas bestimmtes enthält (.contains("ABC")) und dann lasst du das einfach aus.
 
Da ist mein Problem. Wie lasse ich denn die ganze Zeile/den ganzen Datensatz aus? Habe irgendwie kein Code-Beispiel gefunden, welches ich auf mein Problem anwenden könnte.
 
Vielleicht so:
Java:
    ...
    String[][] data = new String[rowCount][columnCount];
            for (int x = 0; x < rowCount; x++) {
                for (int y = 0; y < columnCount; y++) {
                    data[x][y] = oneDdata.remove(0);
                    if (data[x][y].contains("ABC") {
                        x--;     // wieder eine Zeile zurückhupfen
                        break; // und aus der Schleife fuer die Spalten rausgehen
                    }
                }
    ...

Danach stimmt allerdings der rowCount nicht mehr ! Den müsstest du evtl. auch noch korrigieren. Ich weiss, es wäre noch schöner wenn man es weiter oben beim lineScan machen würde
 
Besser so:

Java:
while (lineScan.hasNextLine()) {
            String line = lineScan.nextLine();
            if (line.contains("ABC") {
               continue;
            }
            s = new Scanner(line);
            s.useDelimiter(";");  //der Delimiter war falsch gesetzt, so dass die Tabelle falsch ausgegeben wurde
            while (s.hasNext()) {
                oneDdata.add(s.next().trim());  //hier hatten sich whitespaces versteckt
            }
        }
 

Neue Themen


Zurück
Oben