csv 到 2D 双数组

csv to 2D double array

我正在尝试将 csv 电子表格转换为双二维数组。我设法将 csv 转换为二维字符串数组。我现在正在尝试将其转换为双精度。我得到一个 NumberFormatException 我相信这是因为当我尝试 Double.parseDouble, 它一直在读取列 header 这是一个字符串。它也可能是我的 csv 中的逗号?不确定我的下一步是什么。

public class Filetester {
    private String myArray [][] = new String [50][]

public Filetester(String filename) throws IOException {
    File file = new File(filename);
    Scanner s = new Scanner(file);
    String delimiter = ",";
    int count = 0;
    s.nextLine();
    while (s.hasNextLine()) {
        count++;
        String line = s.nextLine();
        //System.out.println(line);
        String[] arrayAsString = line.split("\s*" + delimiter + "\s*";
        myArray[count] = arrayAsString;
        double[] arrayAsDouble = new double [arrayAsString.length];
        for (int i = 0; i < arrayAsString.length; i++) {
            arrayAsDouble[i] = Double.parseDouble(arrayAsString[i].replaceAll(",", "");
       }
 }

}

我的 csv 看起来像这样

A, B, C, D 
1.0, 2.0, 3.0, 4.0
13.0, 2.0, 3.0, 4.0
1.0, 2.0, 3.0, 4.0

我认为这里的一些建议可能会对您有所帮助,但请记住,对于您的特定应用程序,我不知道您的最终目标是什么。

我看到的是一个 class (Filetester),它包含一个名为 myArray[][] 的实例成员字符串数组变量。我不明白为什么你想要它成为一个 String Array 而你实际上正在寻求实现 double[][] 数据类型数组.我建议您将其声明为可以通过 Getter method once the Filetester class has been instantiated 访问的 double[][] 类型数组。并且,不要初始化此变量,现在您不知道 class 构造函数中提供的 CSV 文件中可能包含多少数据。在实际实例化 Filetester class 时执行此操作:

public class Filetester {

    private double[][] csvFileDoubles;
    
    // Contructor
    public Filetester(String filename) {

    }

    // Getter Method
    public double[][] getCSVFileDoubles() {
        return csvFileDoubles;
    }
}

就目前而言,Filetester 对象只有在其构造函数中为 Filetester class 现在这已经足够好了,但我认为将所有代码都塞入该构造函数并不是一个好主意。在你的构造函数中保持简单和可读。从构造函数中调用一个方法来执行任何任务,例如:

public class Filetester {

    private double[][] csvFileDoubles;  // Default is null.
    
    // Contructor
    public Filetester(String filename) {
        this.csvFileDoubles = getDoublesFromCSV(filename, ",");
    }
    
    public double[][] getCSVFileDoubles() {
        return csvFileDoubles;
    }

    /* Returns a 2D double type Array (double[][]) from the data contained
       within the supplied CSV data file. It is expected that you also supply
       the delimiter used within that supplied CSV file. Any CSV file supplied
       to this method is also expected to contain a Column Names Header Line
       as the very first line of the file.                               */
    private double[][] getDoublesFromCSV(String csvFilePath, String delimiter) {

    }

}

您会在这里注意到一些事情。首先,实例成员数组变量 csvFileDoublesgetDoublesFromCSV() 方法初始化和填充,这仅在实例化 Filetester 时发生。

其次,csvFileDoubles数组变量和getDoublesFromCSV()方法都声明为private,这意味着获取 csvFileDoubles 数组内容的唯一方法是调用 getCSVFileDoubles() Getter 方法,该方法声明为 public 而且,getDoublesFromCSV() 方法只能通过 Filetester class 构造函数调用。

getDoublesFromCSV() 方法是 Filetester class 的实际主力(到目前为止)。它可以检索您想要的 CSV 数据,并将其 returns 存储在 double 数据类型数组中。稍后您很可能会在此 class 中使用其他方法来完成同样多的工作。我建议您阅读该方法中的所有注释。这是整个 Filetester class 的样子:

public class Filetester {

    private double[][] csvFileDoubles;  // Default is null.
    
    // Contructor
    public Filetester(String filename) {
        this.csvFileDoubles = getDoublesFromCSV(filename, ",");
    }
    
    public double[][] getCSVFileDoubles() {
        return csvFileDoubles;
    }

    /* Returns a 2D double type Array (double[][]) from the data contained
       within the supplied CSV data file. It is expected that you also supply
       the delimiter used within that supplied CSV file. Any CSV file supplied
       to this method is also expected to contain a Column Names Header Line. */
    private double[][] getDoublesFromCSV(String csvFilePath, String delimiter) {
        /* A list collection can grow dynamically so it really 
           doesn't matter how many data lines are contained
           within the CSV file. You don't need to worry about
           it.                                              */
        java.util.List<Double[]> doublesList= new java.util.ArrayList<>(); 
        
        // 'Try With Resources' use here so to auto-close reader when done.
        try (java.util.Scanner reader = new java.util.Scanner(new java.io.File(csvFilePath))) {
            /* Read the header line before processing the data lines.
               In this case, we want to ignore it.                 */
            String line = reader.nextLine();  

            // Read through all the other CSV file data lines...
            while (reader.hasNextLine()) {
                line = reader.nextLine();   // Sequencially, read in a line
                if (line.trim().isEmpty()) {
                    // If for some reason the line read is blank then ignore it.
                    continue;
                }
                // Split the read line into columnar parts based on the supplied delimiter.
                String[] lineParts = line.split("\s*" + delimiter + "\s*");
                /* Convert the numerical string value in each column of 
                   the read in line into an element of a 'Double' data 
                   type array so to prep for addition to the List.                */
                Double[] linePartsAsDouble = new Double[lineParts.length];
                for (int i = 0; i < lineParts.length; i++) {
                    /* Confirm the column data is actually a String representation
                       of a numerical value so as to prevent the possibility of a
                       'NumberFormatException'. We use the String#matches() method
                       for this with a small Regular Expression (regex). If confir-
                       mation fails then (for this demo) we're going to make it -1.0.
                       Use whatever you like here. The regex used ensures that a string
                       representation of either a signed or unsigned integer or 
                       floating point numerical value was supplied.             */
                    if (!lineParts[i].matches("-?\d+(\.\d+)?")) {
                        lineParts[i] = "-1.0";
                    }
                    linePartsAsDouble[i] = Double.parseDouble(lineParts[i]);
                }
                // Add the created Double[] data type array into the List/
                doublesList.add(linePartsAsDouble);
                
                // Go and read in next line (if there is one)...
            }
        }
        catch (java.io.FileNotFoundException ex) {
            // Display the 'FileNotFoundException' and returns null.
            System.err.println("getDoublesFromCSV() Method Error!");
            System.err.println(ex.getMessage());
            return null;
        }
        
        /* All is good so far so convert List<Double[]> to a primitive
           double[][] type array and return it.                     */
        double[][] dblArray = new double[doublesList.size()][];
        for (int i = 0; i < doublesList.size(); i++) {
            for (int j = 0; j < doublesList.get(i).length; j++) {
                // Streams (Java 8+) is used here to convert from Double to double.
                dblArray[i] = java.util.stream.Stream.of(doublesList.get(i))
                                .mapToDouble(Double::doubleValue).toArray();
            }
        }
        return dblArray;  
    }
}

而且,这里是你如何使用这个 Filetester class:

public class DemoApp {
 
    public static void main(String[] args) {
        /* Create an instance of Filetester. Supply the full
           path and file name to the Constructor. If you just
           supply the file name as shown below then that file 
           must be contained within the root of your app's 
           Project directory.                             */
        Filetester test = new Filetester("DoublesData.csv");
        
        /* call the Filetester.getCSVFileDoubles() getter
           method to retrieve the generated 2D double[][]
           array.                                       */           
        double[][] dblArray = test.getCSVFileDoubles();
        
        // Display the contents of the 2D Array (dblArray[][])
        for (int i = 0; i < dblArray.length; i++) {
            System.out.println(java.util.Arrays.toString(dblArray[i]));
        }
    }
}

使用您提供的示例浮点文件数据,如果您创建一个名为 DemoApp 的项目并将上述两个 classes 放入其中并放置示例数据进入位于项目根目录中名为 DoublesData.csv 的文件,然后当应用程序处于 运行 时,您会在控制台 window 中看到以下结果:

[1.0, 2.0, 3.0, 4.0]
[13.0, 2.0, 3.0, 4.0]
[1.0, 2.0, 3.0, 4.0]