我使用一个模拟程序,该程序会在后台生成一个包含模拟数据(例如,道路的长度,模拟的时间等)的CSV文件
文件外观的一个示例:
因此,在这种情况下,我知道只有一辆汽车(因为有carId)。现在,如果生成另一个CSV且模拟包含2辆汽车,则列会更改:
因此,您可以看到添加了不同的列(它们很多都不相关,因为我只需要carId和mph)。
如果有越来越多的汽车,那么列数会增加,而我不知道带有mph的carId在哪个位置。
我想要为具有mph外观的每个carId创建一个CarObject。
java中是否有一种方法可以为每个(carId,mph)列创建一个自己的表。所以我有例如。 SELECT
*
FROM
dates_table d
CROSS JOIN
states_table s
LEFT JOIN
data_table t
ON t.date_value = d.date_value
AND t.state_id = s.state_id
WHERE
d.date_value BETWEEN x AND y
AND s.state_id IN (1, 2)
和CarDataRows就像一个List,其中每个项都包含具有特定英里数的carId。
编辑
在这种情况下,集合应包含两个项目。并且Item中的值也应该像一个列表,其中包含带有不同mph的carId。
List<CarDataRows>
例如,在phyton中,您可以使用panda并创建foreach模式(带有mph的carId)和自己的数据框。这就是我在这里要做的
答案 0 :(得分:0)
您的CSV看起来很奇怪,我不希望人们添加列,而是添加行,尤其是当您有一个ID列来区分行时。
也就是说,我将数据解析为Car对象,然后对其进行处理。这涉及三个步骤。
在文件的第一行上,找到指示有趣列的标题字段,此处为carId
和mph
。 Apache的CSV库在重复的标头名称上令人窒息(我不能为此怪罪),因此您需要找到一个更宽松的库或自己解析标头。
利用标题中的信息,创建Car对象,并告诉它们其列。每辆车负责自己的列号以及所有速度(您真正想要的信息)。
然后,您将阅读文件的其余部分,并将速度分配给他们的汽车。由于汽车拥有其数据(其列号和速度),因此您只需将每个记录字段传递给所有汽车,并要求它们对它们进行操作(Tell Don't Ask principle)。
您的Car类可能是这样的:
import java.util.List;
import java.util.ArrayList;
public class Car {
private int id;
private final int idColumn;
private final int speedColumn;
private List<Integer> speeds;
public Car(int idColumn, int speedColumn) {
id = 0;
this.idColumn = idColumn;
this.speedColumn = speedColumn;
speeds = new ArrayList<>();
}
public void add(int column, String value) {
if (this.idColumn == column) {
int i = Integer.parseInt(value);
if (id != 0 && id != i) {
throw new IllegalStateException("changed ID from " + id + " to " + i);
}
id = i;
}
if (this.speedColumn == column) {
speeds.add(Integer.parseInt(value));
}
}
public List<Integer> getSpeeds() {
return speeds;
}
}
然后,使用Apache Common CSV解析器像这样处理CSV输入:
import java.io.*;
import java.util.*;
import org.apache.commons.csv.*;
public class YourCarCsvParser {
/** Column name for a car's ID. */
private static String CAR_ID = "carId";
public static void main(String[] args) throws Exception {
App app = new App();
for (String a : args) {
app.parse(new InputStreamReader(new FileInputStream(a)));
}
}
public List<Car> parse(Reader input) throws IOException {
// Initialize the list so you'll get an empty list not null if there is no CSV data.
List<Car> cars = new ArrayList<>();
CSVParser parser = CSVParser.parse(input, CSVFormat.RFC4180);
boolean hadHeaders = false;
for (CSVRecord record : parser) {
if (!hadHeaders) {
cars = makeCars(record);
hadHeaders = true;
}
else {
addSpeedsToCars(cars, record);
}
}
return cars;
}
private List<Car> makeCars(CSVRecord record) {
List<Car> cars = new ArrayList<>();
for (int i = 0; i < record.size(); i++) {
String field = record.get(i);
if (CAR_ID.equals(field)) {
cars.add(new Car(i, speedColumnFor(i)));
}
}
return cars;
}
private int speedColumnFor(int idColumn) {
// Assumes speed is always right of car ID.
return idColumn + 1;
}
private void addSpeedsToCars(List<Car> cars, CSVRecord record) {
for (int i = 0; i < record.size(); i++) {
for (Car c : cars) {
c.add(i, record.get(i));
}
}
}
}
这会将您的CSV转换为汽车列表,每辆汽车都包含其速度列表。
此代码基于一些假设,但您可能可以根据需要轻松修复它们:
CSV中的列名区分大小写。如果不是,请在检查equals
时将equalsIgnoreCase
更改为CAR_ID
。
速度列位于汽车ID列的旁边:如果不是这种情况,请调整speedColumnFor
方法以返回适当的列。当您没有固定的偏移量但需要查看标题时,例如在看到ID列后选择以下mph标题时,这将变得更加棘手。在这种情况下,您将不得不调整逻辑makeCars
来记住ID列的位置,并且只有在遇到mph列时才使用记住的ID列的位置来创建Car
。
汽车ID是整数,就像您的示例数据中一样。您也可以将它们更改为字符串。
速度是整数。如果需要浮点数,请在从字符串转换时将Integer.parseInt
调整为Float.parseFloat
。