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 读入字符串 [] ,然后到 int[] 并保存到 Vector。然后我创建了一个非常低效的循环来完成这项工作。我需要这个到 运行 尽快,因为我将使用非常大的 csv 有很多不同的 x 和y. 我想到的,但是不知道怎么做的是:
- 在阅读循环中计算这些总和
- 以不同的方式求和,不总是向后循环 x 个成员(保存最后的和然后减去旧的并添加新成员,或者其他更快的方法来进行子数组求和)
- 使用 intStream 和并行(并行可能会很棘手,因为最后我正在寻找 max )
- 使用与 csv 不同的输入?
- 以上都是?
我怎样才能尽快做到这一点?谢谢
您可以尝试在阅读输入时创建一些总和。使用 Integer,Integer
类型的 HashMap 也可能是可行的
由于是每行求和,所以不需要先全部读入内存。
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
总是自动关闭。即使出现异常或 return.
并行度和重新格式化问题后
您可以阅读所有行
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 };
});
我需要从大型 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 读入字符串 [] ,然后到 int[] 并保存到 Vector。然后我创建了一个非常低效的循环来完成这项工作。我需要这个到 运行 尽快,因为我将使用非常大的 csv 有很多不同的 x 和y. 我想到的,但是不知道怎么做的是:
- 在阅读循环中计算这些总和
- 以不同的方式求和,不总是向后循环 x 个成员(保存最后的和然后减去旧的并添加新成员,或者其他更快的方法来进行子数组求和)
- 使用 intStream 和并行(并行可能会很棘手,因为最后我正在寻找 max )
- 使用与 csv 不同的输入?
- 以上都是?
我怎样才能尽快做到这一点?谢谢
您可以尝试在阅读输入时创建一些总和。使用 Integer,Integer
类型的 HashMap 也可能是可行的由于是每行求和,所以不需要先全部读入内存。
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
总是自动关闭。即使出现异常或 return.
并行度和重新格式化问题后
您可以阅读所有行
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 };
});