【问题标题】:Java streams collect excel CSV to a list filtering based on the sum of a columnJava 流将 excel CSV 收集到基于列的总和过滤的列表中
【发布时间】:2021-02-16 17:28:25
【问题描述】:

假设我们有一个如下所示的 excel 电子表格:

StatusCount  FirstName  LastName  ID
1            Tod        Mahones   122145
0            Tod        Mahones   122145
1            Tod        Mahones   122145
-1           Tod        Mahones   122145
1            Ronny      Jackson   149333
1            Eliza      Cho       351995
-1           Eliza      Cho       351995
1            James      Potter    884214
1            James      Potter    884214
-1           Peter      Walker    900248
1            Zaid       Grits     993213

我如何才能将状态计数总和大于 0 的人的 ID 收集到一个列表中,如果它是 0 或更少,则将其丢弃。所以在上面的excel电子表格中,java中的列表应该是这样的:

List<Integer> = [122145, 149333, 884214, 993213]

更新(添加到目前为止我尝试过的内容):

List<Integer> = csvFile.stream()
                       .map(Arrays::asList)
                       .filter(column -> column.get(0).equalsIgnoreCase("1")
                       .map(column -> column.get(3))
                       .map(Integer::parseInt)
                       .sorted()
                       .collect(Collectors.toList());

我只是通过状态计数 1 来收集它们,但这不是正确的过程,它应该是总结每个人或 ID 的状态计数(我想找到任何骗子都很好),如果它 > 0 则收集到列表中,如果没有则丢弃。

更新 2:我忘了提到 csv 文件作为 List 带入 java,其中 List 包含 csv 的行,而 String[] 是行的内容,所以它会就像:

[[1, Tod, Mahones, 122145],[0, Tod, Mahones, 122145], [1, Tod, Mahones, 122145], ...]

【问题讨论】:

  • 到目前为止你做了什么?
  • @iota 添加了我的尝试,谢谢,已经尝试了一段时间没有成功:(

标签: java excel csv java-stream


【解决方案1】:

以下应该有效:

  1. 使用Collectors.groupingBy + Collectors.summingInt 创建Map&lt;Integer, Integer&gt; 以汇总每个ID 的状态
  2. 过滤中间映射条目并将键 (ID) 收集到列表中。

如果应按照输入文件中的方式维护 ID 的顺序,则可以在构建地图时提供 LinkedHashMap::new 作为参数。

public static List<Integer> getIDs(List<String[]> csvFile) {
    return csvFile.stream()
        .map(Arrays::asList) 
        .collect(Collectors.groupingBy(
            column -> Integer.parseInt(column.get(3)),
            LinkedHashMap::new, // optional argument to maintain insertion order
            Collectors.summingInt(
                column -> Integer.parseInt(column.get(0))
        )))
        .entrySet()
        .stream()
        .filter(e -> e.getValue() > 0)
        .map(Map.Entry::getKey)
        .collect(Collectors.toList());
}

测试

List<String[]> csvFile = Arrays.asList(
    new String[] {"1", "Tod", "Mahones", "122145"},
    new String[] {"0", "Tod", "Mahones", "122145"},
    new String[] {"1", "Tod", "Mahones", "122145"},
    new String[] {"-1", "Tod", "Mahones", "122145"},
    new String[] {"1", "Ronny", "Jackson", "149333"},
    new String[] {"1", "Eliza", "Cho", "351995"},
    new String[] {"-1", "Eliza", "Cho", "351995"},
    new String[] {"1", "James", "Potter", "884214"},
    new String[] {"1", "James", "Potter", "884214"},
    new String[] {"-1", "Peter", "Walker", "900248"},
    new String[] {"1", "Zaid", " Grits", "993213"}
);

System.out.println(getIDs(csvFile));

输出

[122145, 149333, 884214, 993213]

【讨论】:

  • 让我试试这个然后回复你,谢谢!
  • 你能检查我的更新吗,如果 csvfile 的类型是 List ,这仍然适用吗?
  • 是的,我用List&lt;String[]&gt;结构对其进行了测试,并提供了相关结果。
【解决方案2】:

下面的代码应该很好用:

  1. 按 ID 对总和进行分组
  2. 从该 Map 中删除总和为非正数的条目
  3. 检索包含唯一 ID 的 keySet
List<String[]> csvFile = new ArrayList<>();
csvFile.add(new String[]{"1", "Tod", "Mahones", "122145"});
csvFile.add(new String[]{"0", "Tod", "Mahones", "122145"});
csvFile.add(new String[]{"1", "Tod", "Mahones", "122145"});
csvFile.add(new String[]{"-1", "Tod", "Mahones", "122145"});
csvFile.add(new String[]{"1", "Ronny", "Jackson", "149333"});
csvFile.add(new String[]{"1", "Eliza", "Cho", "351995"});
csvFile.add(new String[]{"-1", "Eliza", "Cho", "351995"});
csvFile.add(new String[]{"1", "James", "Potter", "884214"});
csvFile.add(new String[]{"1", "James", "Potter", "884214"});
csvFile.add(new String[]{"-1", "Peter", "Walker", "900248"});
csvFile.add(new String[]{"1", "Zaid", "Grits", "993213"});

Map<String, Integer> intermediateMap = csvFile.stream()
        .map(Arrays::asList)
        .collect(Collectors.groupingBy(
                x -> x.get(3),
                Collectors.summingInt(
                        x -> Integer.parseInt(x.get(0))
                )
        ));

intermediateMap.entrySet().removeIf(e -> e.getValue() <= 0);

Set<String> ids = intermediateMap.keySet();

System.out.println(ids); // [122145, 149333, 884214, 993213]

【讨论】:

  • 你能检查我的更新吗,如果 csvfile 的类型是 List ,这仍然适用吗?
  • @stackerstack 当然,等一下,我会粘贴我测试过的整个代码 sn-p
【解决方案3】:

由于CSV文件是按ID列排序的,所以可以按ID对行进行分组,对每组的StatusCount值求和,找出总和大于0的ID。需要熟悉Stream Collectors,否则很难实现算法。

然而,使用开源 Java 包 SPL 很容易表达该过程。一行代码就够了,

A
1 =file("data.csv").import@ct().groups@o(ID;sum(StatusCount)).select(#2>0).(#1)
....
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call filter()");
st.execute();
…

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 2017-09-22
    • 2016-07-14
    • 2014-08-02
    • 1970-01-01
    相关资源
    最近更新 更多