[英]CSV to list of double arrays
我试图将csv文件的内容放入双数组列表中。 我有一个类型为double []的列表,并想知道如何填充其中的数组。
List <Double[]> lines = new ArrayList<Double[]>();
我之前通过执行以下操作为这些数组添加了值
while ((thisLine = br.readLine()) != null){ //while there is a line to read
String newLine = thisLine.replace("station_readings,", ""); //replace station headings with blank
lines.add(newLine.split(","));
但这仅在列表由字符串数组组成时才有效。
无论如何,将此csv文件中的内容放入双打数组中。
CSV内容示例:
name,time,frequency,targetPower,power,stateOfCharge
station_readings,2018-04-27T14:04:00.2Z,49932,273.093,294.469,49.2343
station_readings,2018-04-27T14:04:00.3Z,49922,313.299,292.487,49.2269
station_readings,2018-04-27T14:04:00.4Z,49932,273.093,292.235,49.2269
所有建议都赞赏。
提前致谢。
(注意 - 我应该得到一个新的csv,其中日期格式以ms为单位,而不是如何在此处显示,从而使csv中的所有值都为“数字”)
我将流文件中的行,然后拆分每一行并单独流式传输:
List<double[]> lines =
Files.lines(Pathes.get("/path/to/file.csv"))
.skip(1) // Skip the heading
.map(line -> Arrays.stream(line.split(","))
.skip(1) // Skip the "station_readings"
.mapToDouble(Double::parseDouble)
.toArray()
)
.collect(Collectors.toList());
编辑:
@ user7刚刚指出OP正在寻找List<Double[]>
。 这当然也可以以类似的方式:
List<Double[]> lines =
Files.lines(Pathes.get("/path/to/file.csv"))
.skip(1) // Skip the heading
.map(line -> Arrays.stream(line.split(","))
.skip(1) // Skip the "station_readings"
.map(Double::new)
.toArray(Double[]::new)
)
.collect(Collectors.toList());
如果您的CSV的每一行都有格式
station_readings,2018-04-27T14:04:00.3Z,49922,313.299,292.487,49.2269
前两列的数据无法解析为double
。
因此,您只能解析剩余的列。
实现此目的的一种方法是将所有行读取到thisLine
变量中。
在此之后,您可以拆分分隔符以获取字符串数组:
String[] rowRaw = thisLine.split(",");
然后你可以将它从第3个元素迭代到结尾,将其解析为double并将其放入适当的slzed double[]
。 然后可以将其添加到您的列表中。
double[] row = new double[rowRaw.length - 2];
for (int i=2; i<rowRaw.length; i++) {
row[i - 2] = Double.parseDouble(rowRaw[i]);
}
lines.add(row);
如果要将第二列(时间戳字符串)解析为有意义的数字,可以按如下方式进行迭代
double[] row = new double[rowRaw.length - 1];
row[0] = toDouble(rowRaw[1]);
for (int i=2; i<rowRaw.length; i++) {
row[i - 2] = Double.parseDouble(rowRaw[i]);
}
lines.add(row);
使用一种方法将字符串转换为double(时间戳长存储为double)。 你可能不得不调整它,它没有经过测试。
double toDouble(String tsStr) {
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
sdf.setTimeZone(utc);
Date date = sdf.parse(tsStr);
return Double.longBitsToDouble(date.getTime());
}
首先,您可能想要使用double[]
,而不是Double[]
。 “Double”和“double”不一样 - 大写版本是一个类,这意味着它产生的开销远远超过一个简单的数字,这只是几个字节。
无论哪种方式,您都可以使用Double.parseDouble转换每个CSV字段,但日期字段除外,可以使用Instant.parse进行解析:
String[] fields = thisLine.split(",");
double[] values = new String[fields.length - 1];
Instant dateTime = Instant.parse(fields[1]);
values[0] = dateTime.toEpochMilli();
for (int i = 2; i < fields.length; i++) {
values[i - 1] = Double.parseDouble[fields[i]);
}
lines.add(values);
您的评论表明,真实的CSV与您共享的示例CSV不同。 在这种情况下,您可以跳过使用Instant:
String[] fields = thisLine.split(",");
double[] values = new String[fields.length - 1];
for (int i = 1; i < fields.length; i++) {
values[i - 1] = Double.parseDouble[fields[i]);
}
lines.add(values);
但是,作为一个好的设计,你根本不应该使用数组。 您应该定义一个数据类,因此每个double值的含义都是明确的:
import java.time.Instant;
import java.util.Objects;
public class StationReading {
private final String name;
private final Instant time;
private final double frequency;
private final double targetPower;
private final double power;
private final double stateOfCharge;
public StationReading(String name,
Instant time,
double frequency,
double targetPower,
double power,
double stateOfCharge) {
this.name = name;
this.time = time;
this.frequency = frequency;
this.targetPower = targetPower;
this.power = power;
this.stateOfCharge = stateOfCharge;
}
public String getName() {
return name;
}
public Instant getTime() {
return time;
}
public double getFrequency() {
return frequency;
}
public double getTargetPower() {
return targetPower;
}
public double getPower() {
return power;
}
public double getStateOfCharge() {
return stateOfCharge;
}
@Override
public String toString() {
return getClass().getSimpleName() +
"[name=\"" + name + "\"" +
", time=" + time +
", frequency=" + frequency +
", target power=" + targetPower +
", power=" + power +
", state of charge=" + stateOfCharge +
"]";
}
public static StationReading fromLine(String line) {
Objects.requireNonNull(line, "Line cannot be null.");
String[] fields = line.split(",");
if (fields.length != 6) {
throw new IllegalArgumentException(
"Cannot parse a line unless it has exactly six fields.");
}
String name = fields[0];
Instant time = Instant.parse(fields[1]);
// When you get a new CSV which represents times in milliseconds,
// change the above to:
//
// double ms = Double.parseDouble(fields[1]);
// Instant time = Instant.ofEpochMilli((long) ms);
// time = time.plusNanos((long) ((ms - Math.floor(ms)) * 1_000_000));
double frequency = Double.parseDouble(fields[2]);
double targetPower = Double.parseDouble(fields[3]);
double power = Double.parseDouble(fields[4]);
double stateOfChange = Double.parseDouble(fields[5]);
return new StationReading(name, time,
frequency, targetPower, power, stateOfChange);
}
}
现在,您的读取循环很简单:
List<StationReading> readings = new ArrayList<>();
while ((thisLine = br.readLine()) != null) {
StationReading reading = StationReading.fromLine(thisLine);
readings.add(reading);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.