【问题标题】:Filling a double[][] from the CSV file从 CSV 文件填充 double[][]
【发布时间】:2018-01-29 04:12:21
【问题描述】:

我有这个 CSV 文件:

World Development Indicators
Number of countries,4
Country Name,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014
Bangladesh,6.28776238,13.20573922,23.46762823,30.16828408,34.35334451,44.94535882,55.19256723,62.82023906,74.42964608,80.03535051
"Bahamas, The",69.21279415,75.37855087,109.340767,102.7875065,101.2186453,118.8292307,81.5628489,80.65383375,76.05187427,82.29635806
Brazil,46.31418452,53.11025849,63.67475185,78.5549801,87.54187651,100.8810115,119.0023853,125.0018521,135.3050481,138.9514906  
Germany,94.55486999,102.2828888,115.1403608,126.5575074,126.2280577,106.4836959,109.6595675,111.5940398,120.9211651,120.4201855

我正在尝试将国家/地区的数据(双倍一次)存储到一个矩阵(双倍 [][])中。这是我到目前为止的代码:

public double[][] getParsedTable() throws IOException {
    double[][] table = new double[4][10];
    String row;
    int indexRow = 0;
    int indexColumn = 0;
    BufferedReader br = new BufferedReader(new FileReader(fileName));
    br.readLine();
    br.readLine();
    String line = br.readLine();
    while(line != null && !line.isEmpty()){
        line = br.readLine();
        String[] array = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
        for(int i = 1; i < array.length; i++){
            table[indexRow][indexColumn] = Double.parseDouble(array[i]);
            indexColumn++;
        }
        indexColumn = 0;
        indexRow++;
    }
    System.out.print(Arrays.deepToString(table));
    return table;
}

我得到一个错误:NullPointerException at:

String[] array = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);

我不知道为什么。我尝试了不同的组合。似乎没有任何效果。它似乎从 CSV 文件中提取数字并存储它们,但是当我调用时:

System.out.print(Arrays.deepToString(table));

它不会打印出任何东西,因此我无法检查它是否正确存储。能否告诉我:1. Why I am getting an error. 2. Why System.out.println does not print out an array. 谢谢

【问题讨论】:

  • 您的 CSV 文件格式不正确,标题必须在行首
  • @ArifMustafa 这个 CSV 文件由我的导师提供。我不能改变它。
  • 查看此维基CSV example

标签: java arrays csv


【解决方案1】:

如果我们假设一个国家/地区的名称不包含数字并且国家名称和数字将仅用逗号分隔,那么可以在没有正则表达式的情况下完成以下操作。我稍微更改了文件读取,因为它可能会遇到问题。

public double[][] getParsedTable() throws IOException {
    double[][] table = new double[4][10];
    int indexRow = 0;
    int indexColumn = 0;
    BufferedReader br = new BufferedReader(new FileReader(fileName));
    br.readLine(); // ignore first line
    br.readLine(); // ignore second line
    br.readLine(); // ignore third line (contains title)
    String line;
    while (true) {
        line = br.readLine();
        if (line == null) break; // end of file reading

        int index = 0;
        while (true) {
            index = line.indexOf(",", index) + 1;
            if (Character.isDigit(line.charAt(index))) {
                break;
            }
        }

        // from index, line is expected to contain comma separated numbers
        String[] array = line.substring(index).split(",");
        for (int i = 0; i < array.length; i++) {
            table[indexRow][indexColumn] = Double.parseDouble(array[i]);
            indexColumn++;
        }
        indexColumn = 0;
        indexRow++;
    }
    System.out.print(Arrays.deepToString(table));
    return table;
}

【讨论】:

  • 非常感谢。
【解决方案2】:

在 csv 中,前 3 行不是真实国家/地区的数据。所以在while循环开始之前读入line-4

在while循环中,先完成对line字符串的处理。例如:正则表达式检查并将拆分数据分配到table

然后只在while循环结束时读入next line,在下一次迭代中处理。

随意尝试一下:

public double[][] getParsedTable() throws IOException {
    double[][] table = new double[4][10];
    int indexRow = 0;
    int indexColumn = 0;

    // check whether you need to handle any exception for this
    BufferedReader br = new BufferedReader(new FileReader(fileName));

    String line = null;

    try {
        // line 1-3 are not real country's data
        br.readLine();
        br.readLine();
        br.readLine();

        // first country data begin at line 4
        line = br.readLine();
    } catch (IOException e) {
        e.printStackTrace();
    }

    while (line != null && !line.isEmpty()) {            
        String[] array = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);

        for (int i = 1; i < array.length; i++) {
            table[indexRow][indexColumn] = Double.parseDouble(array[i]);
            indexColumn++;
        }

        indexColumn = 0;
        indexRow++;

        // read next line only at end of loop, not beginning of loop
        // line is ready to be processed at next iteration
        try {
            line = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    System.out.print(Arrays.deepToString(table));
    return table;
}

【讨论】:

  • 这可行,但上面的人提供了一个更简单的版本。不过,感谢您的努力。
【解决方案3】:

Arrays.deepToString 是错误的。您正在传递一个基元数组。当你传入它时,你传入了 double[][]。这被解释为 Object[],其中对象是 double[],因此它将尝试打印 double[] 对象,而不是打印双精度。

一种解决方案是创建一个数组 Double[][]。

改变

 double[][] table = new double[4][10];

 Double[][] table = new Double[4][10];

自动装箱会将每个双精度转换为双精度。由于 Double 是一个对象而不是原始类型,因此 deepToString 将单独打印出每个 Double。如果您阅读 deepToString 的 javadoc,它会解释它在引用类型的数组上递归操作,而不是在原始数组上。

如果你想坚持使用 double[][]

for (int i = 0; i < table.length; i++) {
    for (int j = 0; j < table[i].length; j++) {
        System.out.print(table[i][j]);
        System.out.print(' ');
    }
    System.out.println();
}

【讨论】:

  • 那是因为如果我执行 line.split(",") 一旦 readLine() 命中“Bahamas, The”就会出错,因为其中包含字符。
  • 我明白了。在这种情况下,您知道您想要每行中的最后 10 个条目。所以无论你最终有多少条目,都取最后 10 个。
  • 更改了我的答案以提供两个选项。
  • 不幸的是,这并不能解决我的任何问题
  • 好的,再给你一个解决方案,你对 deepToString 的使用是错误的。
猜你喜欢
  • 2013-05-12
  • 2013-11-25
  • 2020-06-01
  • 2019-07-23
  • 2011-02-22
  • 2014-01-27
  • 2017-04-17
  • 2019-08-16
  • 2018-10-02
相关资源
最近更新 更多