簡體   English   中英

Java讀取CSV +子數組的特定總和-最有效的方法

[英]java read csv + specific sum of subarray - most efficient way

我需要從大型csv中讀取整數,然后對它們進行特定的求和。 目前,我有以下算法:

String csvFile = "D:/input.csv";
String line = "";
String cvsSplitBy = ";";
Vector<Int[]> converted = new Vector<Int[]>();

try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {

   while ((line = br.readLine()) != null) {
       String[] a = line.split(";",-1);
       int[] b = new int[a.length]; 
       for (int n = 0, n < a.length(), n++){
          b[n] = Integer.parseInt(a[n]);
       }
       converted.add(b);
   }
} 

catch (IOException e) {
e.printStackTrace();
}

int x = 7;
int y = 5;
int sum = 0;    

for (int m = 0; m < converted.size(); m++){
  for (n = 0, n < x, n++){
      sum = sum + converted.get(m)[n];
  }
  System.out.print(sum + " ");



  for (int n = x + y, n < converted.get(m).length, n = n + y){
      sum = 0;
      for (int o = n -y; o < n; o++)
         sum = sum + converted.get(m)[n];
      }
      System.out.print(sum + " ");
  }
  System.out.println("");
}

我想做的是獲取一個csv行的前x個成員的總和,然后每個+ y獲得x個成員的總和。 (在這種情況下,第一個x-7的總和(0-6的總和),然后是下一個x-7的總和,但之后y-5列的總和(5-11的總和),(10-16的總和)...並將它們寫成每一行。(在最后一個收集行號中,最大值(0-6之和),(5-11之和)。因此,最終結果應為例如5,9,13,155 ... ,這意味着第5行的最大和為0-6,第9行的最大和為5-11 ...)如您所見,這是一種效率很低的方法,首先,我將整個csv讀入string [] ,然后放入int []並保存到Vector中。然后,我創建了一個效率很低的循環來完成工作。我需要使其盡可能快地運行,因為我將使用具有很多x和y的非常大的csv。在考慮,但不知道該怎么做:

  1. 在閱讀循環中做這些總和
  2. 以不同的方式進行求和,並不總是向后循環x個成員(保存最后的總和,然后減去舊的成員並添加新的成員,或者以其他更快的方式進行子數組總和)
  3. 使用intStream和parallelism(並行可能會很棘手,因為最終我正在尋找max)
  4. 使用不同的輸入,然后CSV?
  5. 上述所有的?

我如何盡快做到這一點? 謝謝

由於總和是每行,因此您無需先讀取內存中的所有內容。

Path csvFile = Paths.get("D:/input.csv");
try (BufferedReader br = Files.newBufferedReader(csvFile, StandardCharsets.ISO_8859_1)) {

     String line;
     while ((line = br.readLine()) != null) {
         int[] b = lineToInts(line);
         int n = b.length; 

         // Sum while reading:
         int sum = 0;
         for (int i = 0; i < 7; ++i) {
             sum += b[i];
         }
         System.out.print(sum + " ");

         sum = 0;
         for (int i = n - 5; i < n; ++i) {
             sum += b[i];
         }
         System.out.print(sum + " ");

         System.out.println();
     }
}

private static int[] lineToInts(String line) {
     // Using split is slow, one could optimize the implementation.
     String[] a = line.split(";", -1);
     int[] b = new int[a.length]; 
     for (int n = 0, n < a.length(), n++){
         b[n] = Integer.parseInt(a[n]);
     }
     return b;
}

更快的版本:

private static int[] lineToInts(String line) {
    int semicolons = 0;
    for (int i = 0; (i = line.indexOf(';', i)) != -1; ++i) {
        ++semicolons;
    }
    int[] b = new int[semicolons + 1];
    int pos = 0;
    for (int i = 0; i < b.length(); ++i) {
        int pos2 = line.indexOf(';', pos);
        if (pos2 < 0) {
            pos2 = line.length();
        }
        b[i] = Integer.parseInt(line.substring(pos, pos2));
        pos = pos2 + 1;
    }
    return b;
}

順便說一句:Vector很舊,最好使用List和ArrayList。

List<int[]> converted = new ArrayList<>(10_000);

以上是初始容量的可選參數:萬。

奇怪的try-with-resource語法try (BufferedReader br = ...) {確保br總是自動關閉。 即使有異常或返回。


並行性和重新格式化問題后

您可以閱讀所有行

List<String> lines = Files.readAllLines(csvFile, StandardCharsets.ISO_8859_1);

而不是像這樣玩並行流:

OptionalInt max = lines.parallelStream()
    .mapToInt(line -> {
        int[] b = lineToInst(line);
        ...
        return sum;
    }).max();

要么:

IntStream.range(0, lines.size()).parallel()
    .mapToObj(i -> {
        String line = lines.get(i);
        ...
        return new int[] { i, sum5, sum7 };
    }); 

您可能會在讀取輸入時嘗試創建一些總和。 使用Integer,Integer類型的HashMaps也是可行的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM