提问人:abdelsh 提问时间:4/24/2022 最后编辑:Alexander Ivanchenkoabdelsh 更新时间:4/28/2022 访问量:377
动态选择 CSV 文件中的特定列
Selecting a particular Column in a CSV-file Dynamically
问:
我有这个CSV文件:
id,name,mark
20203923380,Lisa Hatfield,62
20200705173,Jessica Johnson,59
20205415333,Adam Harper,41
20203326467,Logan Nolan,77
我正在尝试使用以下代码处理它:
try (Stream<String> stream = Files.lines(Paths.get(String.valueOf(csvPath)))) {
DoubleSummaryStatistics statistics = stream
.map(s -> s.split(",")[index]).skip(1)
.mapToDouble(Double::valueOf)
.summaryStatistics();
} catch (IOException e) // more code
我想按名称获取该列。
我想我需要验证索引是用户以整数形式输入的列的索引,如下所示:
int index = Arrays.stream(stream).indexOf(columnNS);
但这行不通。
流应具有以下值,例如:
列:"mark"
62, 59, 41, 77
答:
1赞
Alexander Ivanchenko
4/24/2022
#1
我需要验证索引是用户以整数形式输入的列的索引...但这行不通。
Arrays.stream(stream).indexOf(columnNS)
Stream IPA 中没有方法。我不确定你的意思,但这种方法是错误的。indexOf
stream(stream)
为了获取有效的索引,您需要列的名称。根据名称,您必须分析从文件中检索到的第一行。就像在列名“mark”的示例中一样,您需要找出此名称是否存在于第一行中以及它的索引是什么。
我想要的是按它的名字获取该列......溪流应该......
流应该是有状态的。它们是在 Java 中引入的,以便提供富有表现力和清晰的代码结构化方式。即使你设法将有状态条件逻辑塞进一个流中,你也会失去这个优势,最终得到的复杂代码不如普通循环那么清晰(其余部分:迭代解决方案几乎总是表现得更好)。
因此,要保持代码整洁,可以选择:使用迭代方法解决此问题,或者放弃在流中动态确定列索引的要求。
这就是如何使用循环来解决基于列名动态读取文件数据的任务:
public static List<String> readFile(Path path, String columnName) {
List<String> result = new ArrayList<>();
try(var reader = Files.newBufferedReader(path)) {
int index = -1;
String line;
while ((line = reader.readLine()) != null) {
String[] arr = line.split("\\p{Punct}");
if (index == -1) {
index = getIndex(arr, columnName);
continue; // skipping the first line
}
result.add(arr[index]);
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
// validation logic resides here
public static int getIndex(String[] arr, String columnName) {
int index = Arrays.asList(arr).indexOf(columnName);
if (index == -1) {
throw new IllegalArgumentException("Given column name '" + columnName + "' wasn't found");
}
return index;
}
// extracting statistics from the file data
public static DoubleSummaryStatistics getStat(List<String> list) {
return list.stream()
.mapToDouble(Double::parseDouble)
.summaryStatistics();
}
public static void main(String[] args) {
DoubleSummaryStatistics stat = getStat(readFile(Path.of("test.txt"), "mark"));
}
评论
0赞
abdelsh
4/25/2022
我不想获取 main 方法上的值,我想获取另一个方法的值,那么我如何使用 ''' DoubleSummaryStatistics stat = getStat(readFile(csvPath, columnNs));''' 与 getter 和 setters?.getMin()
getMax()
getAverage()
//code public static DoubleSummaryStatistics getStat(List<String> list) { return list.stream() .mapToDouble(Double::valueOf) .summaryStatistics(); } public void setMean(BigDecimal mean) { this.mean = mean; } //more setters
0赞
Alexander Ivanchenko
4/25/2022
@abdelsh 如果要基于 的数据构造自定义对象,您可以创建一个单独的方法负责此。我建议使用构造函数,使用 Builder 模式,而不是 setter。如果您在实现此逻辑时遇到问题,因为它与从文件中读取数据的主题没有直接关系,我建议您打开一个新问题来解决这个问题。DoubleSummaryStatistics
0赞
abdelsh
4/25/2022
效果非常好,但是现在我在计算方面遇到了问题,那么如何对流进行排序,获取它的中间值,或者如果有两个中间值,则获取它们并获取其中位数的最佳方法
0赞
Alexander Ivanchenko
4/25/2022
@abdelsh (docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/...) 可以为您提供平均值、最小值和最大值。要培养中位数,您可以使用如下返回的列表创建一个数组: - 这将给出一个排序的数组。下一步请参阅此处或本教程DoubleSummaryStatistics
double[]
readFile()
readFile().stream().mapToDouble(Double::valueOf).sorted().toArray();
0赞
abdelsh
4/26/2022
如何实现 writeFile 方法来创建新文件并实现它们?我正在做的是尝试在 fileReader 中创建文件,这是下一个代码String[] arr = String.valueOf(csvPath).split("\\\\"); int i = 0; for (i=0; i< arr.length; i++){ } String csvFile = arr[i]; File newFile = new File(csvFile); try { newFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); }
评论
Map<String, Integer>
.map(s -> s.split(",")[Mark.getColumn("id")])