2017-02-09 137 views
0

我有这个功能,它被设想为打开一个文件并读取第一个元素[1st row] [1st column],将其存储在一个3D数组[文件索引] [行] [列],然后打开下一个文件并执行相同的过程。此操作应该一直运行,直到所有文件中的所有行和列都存储在3D数组中。 我的问题是,这个函数做的工作,但它只读取每个文件的第一行(行),并停在那里! 任何专家都可以帮我弄清楚我的功能正在发生什么?我一直在使用Java进行约两一个月了:/java:一次读取所有csv文件并总结元素/行

public static double[][][] fetch_data(int start, int end, int column) throws IOException{ 
    // start and end are for files start and end index. 
    int length = file_length(start); // since all files have the same length. The file_length() function just determine the length. 
    data = new double [number_of_files][length][number_of_columns]; 
    int sum = 0; 
    for (int i = 0; i < length; i++){ 
     for (int index = start; index < end; index++){ 
      Scanner scan = new Scanner (new BufferedReader(new FileReader(file_call(index)))); // file_call() is a function that lookup the file dir. 
      scan.nextLine(); 
       String scanedData = scan.nextLine(); 
       String [] array = scanedData.split(","); 
       data[index][i][colum] = Double.parseDouble(array[index]); 
       sum += data[index][i][colum]; 
       System.out.println(" element " + data[index][i][column]); // just to test the loop 
      } 
     } 
     return data; 
    } 

的数据文件看起来像: 文件(1):

A, B, C, D 
1, 2, 3, 4 
13, 2, 3, 4 
1, 2, 3, 4 
... 

文件(2):

A, B, C, D 
5, 6, 7, 8 
55, 6, 7, 8 
5, 6, 7, 8 
... 

file(3):

A, B, C, D 
9, 10, 11, 12 
9, 10, 11, 12 
91, 10, 11, 12 
... 

exp ected输出(我们忽略了在上面的代码中的第一行的“A,BC,d”):

1+5+9, 2+6+10, ... 
13+55+9, 2+6+10, ... 
1+5+91, 2+6+10, ... 
... 

我希望找到在Java中有人高手谁可以教我如何让我的for循环要经过所有每行都有一个文件行,就像读取所有文件中的第一行并再次返回并读取所有文件中的第二行等等。

我会非常感谢你的帮助球员。

最佳

+0

我建议你使用调试器来浏览你的代码,找出它在做什么。 –

+0

您还应该关闭计算机并拿到一张纸和一支铅笔。用文字写出解决问题的步骤。 –

+0

谢谢你们,我做了调试,这就是我发现它只读取第一行并停止。 –

回答

1

这不是一个loop

if (scan.hasNext()){ 

既然你现在重新创建每次扫描仪,你在每一次文件的顶部开始了。你有几个选择。或者:

  1. (低效率)为每个文件创建的每个迭代一个新的扫描仪,并跳到正确的路线
  2. 保持扫描仪的列表,并读取所有文件一起
  3. 维护文件的列表内容并按顺序读取每个文件

如果您选择选项3,则需要使用另一个循环处理结果。

+0

谢谢,我实际上发现这个“如果”条件在我的代码中没用,我会删除它。但是,正如你所看到的,那里有两个主循环,而第三个在功能之外实现。还是你的意思是别的? –

+0

@AhmedAbdelrahman如果您在我的文章中单击[loop](https://www.tutorialspoint.com/java/java_while_loop.htm),它会带您到关于java while循环的教程。那么你应该考虑它在这个位置可能是有用的,你检查hasNext() –

+0

再次感谢帕特里克,与“while”条件的问题,它不会停止,直到它在一个文件中一次读取所有行,然后移动到下一个文件。虽然我想输出如图所示,每个文件行。我一直在努力挣扎,直到我切换到“for”循环,似乎做了这项工作,但有这个问题。 –

0

我可以看到一些错误的东西在这里:(?拼错)

  1. data[index][i][colum] = Double.parseDouble(array[index]);变量colum没有定义
  2. 在同一行,array[index]行可能不正确,因为你必须读取array中的所有值,而不仅仅是一个值。此外,index是文件索引,而不是array中的索引。您应该循环访问array,其中column是列索引。即:

    for (int column = 0; column < array.length; column++) { 
        data[index][i][column] = Double.parseDouble(array[column]); 
    } 
    
0

如果我没有得到它,也有一些地方在不必要的代码。我会这样做:

  • 初始化一个双数组(我不知道大小是否应该固定 - 现在让我们假设它是固定的 - 您将扩展它更容易)四列和十行:

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

这是零的数组。

  • 现在,假设n是要读取的文件数,让你在for循环(将执行n倍)的所有文件,一个又一个的读取。在for循环中,您使用while循环与hasNext()方法作为条件。在while循环中,您可以读取另一行,将其拆分为数字,然后将相应的数字添加到行中的每个单元格中(您需要额外的迭代器来指定下一行)。

单独行上的大多数操作都是在您发布的代码中完成的,因此它对您而言不应该是一个问题。

这只是一个想法如何去做,希望它有帮助。

第二种方法

我能想到一个办法,而不while循环。考虑使用Scanner类,使用useDelimeter()方法将文件拆分为单独的行,然后将单独的行拆分为数字。您需要阵列n x r x c,其中n是文件数,r行数,c列数。在那里你将存储你的文件中的数据。拥有这个3-dimnesonal数组,你可以以任何你想要的方式轻松添加数值。

+0

Oh man @Michal,你把我的恶梦带回来了,“while”循环!我为什么使用“for”循环的主要原因是因为“while”循环取整个文件,直到它到达文件的最后一行才停止,然后移动到下一个文件,这是我真的不喜欢的东西,不想要。在你的评论“现在,假设n是数字......”这是阅读任何数据文件的常用方法,我试图通过使用“for”循环来覆盖此方法。 –

+0

为什么在'while'循环中读取整个文件不是一个选项?我不明白为什么你不这样做?尤其是,当文件之间的行数不同时,不能从所有文件中读取一行,然后从所有文件中读取第二行,等等,或许可以,但可能会导致问题,使用时不会有问题while循环。 –

+0

当然可以,但没有while循环。这是我切换到循环的平均原因。我设法解决了我的问题,我很快发布了我的解决方案,以帮助其他可能需要它的人。 –

1
private static double[][] getCsv(Path path) { 
    try { 
    return Files.lines(path).map(line -> 
     Arrays.stream(line.split(",")).mapToDouble(Double::valueOf).toArray() 
    ).toArray(double[][]::new); 
    } catch (IOException e) { 
    throw new UncheckedIOException(e); 
    } 
} 

...

Path[] paths = ... 

double[][][] result = Arrays.stream(paths).map(
    path -> getCsv(path) 
).toArray(double[][][]::new); 
+0

谢谢@rustot。这段代码有点超出我的水平,但我花了一些时间来弄清楚。在“getCsv”方法中,你以某种方式将字符串行映射为通过“Files.lines(path).map(...)“,然后将其转换为二维数组,然后通过”结果“将其转换为三维数组。首先,我尝试了这段代码,但似乎有一个问题,我真的不知道”getCsv“方法!也没有看到这将如何从每个文件中取出线,并重复这一点!除非我在循环的文件的索引!!但你的帮助表示赞赏虽然。 –

+0

流 - >做某事 - > toArray()在这种情况下允许在进程结束时分配数组,当实际大小已知时 存在3个嵌套流,例如3个嵌套循环在您的示例中第一个文件名流,来自文件的嵌套流和来自文件的行嵌套流每个流最后崩溃到阵列 – rustot

0

好吧,我设法通过编写以下功能来解决我的小问题。 下面的函数,去读取每个文件中的第一列,并将其视为为x轴存储的值。在这个函数中,我们不会遍历文件索引,因为第一列对于所有文件都是相同的,所以从任何文件取第一列就足够了。如果你的文件不同,那么只需循环遍历文件索引来解释y轴的第二个函数。

//================================= Generate x-data for x-axis 
    public static double[][] get_x_data(int start, int end, int node) throws IOException{ 
     // start: for start file, end: for end file, node: for column 
     // storing the volt column from the first file, we call it base experiment 
     // base file is specified by the user or the machine will take the first file as base by default 
     int base_index = 0; // should be implemented in the gui later 

     if (base_index == 0){ 
      index = 1; 
      @SuppressWarnings("resource") 
      int length = data_vault.file_length(index); // "file_length" is a function that determine the length of the file. 
      String filename = data_vault.file_call(index); // "file_call" is a function that seek the name of the file from some directory. But you can insert you file directly here! 
      data_x = new double [length][end]; 
      Scanner scan = new Scanner (new BufferedReader(new FileReader(filename))); 
      scan.nextLine(); 
      for (int i = 0; i < length; i++){ 
       String scanedData = scan.nextLine(); 
       String [] array = scanedData.split(","); 
       data_x[i][index] = Double.parseDouble(array[0]); 
       x_value = data_x[i][index]; // no need for this 
       //System.out.println("x-axis " + data_x[i][index] + " file index " + index + " read " + i); 
      } 
     } 
     return data_x; 
    } 

功能下面独立地寻求每一列并将其作为y轴的值:其具有,通过每个文件的行(I从0运行到最后一行,长度,运行一个内部循环文件)。这个'i'循环由运行在文件索引(file_1,file_2,...,file_n)上的另一个循环包装。然后所有的函数都被一个遍历列的循环包装。下面是产生y轴的实体功能:

//================================= Generate y-data for y-axis 
public static double[][] get_y_data(int start, int end, int node) throws IOException{ 

    for (int index = start; index < end; index++){ 
     @SuppressWarnings("resource") 
     int length = data_vault.file_length(index); 
     data_y = new double [length][end]; 
     String filename = data_vault.file_call(index); 
     Scanner scan = new Scanner (new BufferedReader(new FileReader(filename))); 
     scan.nextLine(); 
     for (int i = 0; i < length; i++){ 
      String scanedData = scan.nextLine(); 
      String [] array = scanedData.split(","); 
      data_y[i][index] = Double.parseDouble(array[node]); 
      y_value = data_y[i][index]; // no need for this 
      //System.out.println(" y-axis " + y_value); 
     } 
    } 
    return data_y; 
} 

笔记“指数”在这里,用户可以选择从哪里开始读他的文件,从第一或“N”文件开始。索引循环将从'int start'开始并循环,直到'int end'

然后,你可以基本上做任何你想要的这些矩阵。我希望这个解决方案能帮助别人。

最适合你们。