【问题标题】:How to sort data in a CSV file using a particular field in Java?如何使用 Java 中的特定字段对 CSV 文件中的数据进行排序?
【发布时间】:2014-09-04 20:23:45
【问题描述】:

我想读取 Java 中的 CSV 文件并使用特定列对其进行排序。我的 CSV 文件如下所示:

 ABC,DEF,11,GHI....
 JKL,MNO,10,PQR....
 STU,VWX,12,XYZ....

考虑到我想使用第三列对其进行排序,我的输出应该如下所示:

 JKL,MNO,10,PQR....
 ABC,DEF,11,GHI....
 STU,VWX,12,XYZ....

在研究了用什么数据结构来保存CSV的数据后,这里的人建议使用以Integer和List作为键值对的Map数据结构in this question

 Map<Integer, List<String>>
 where the value, List<String> = {[ABC,DEF,11,GHI....], [JKL,MNO,10,PQR....],[STU,VWX,12,XYZ....]...}
 And the key will be an auto-incremented integer starting from 0.

那么任何人都可以建议一种方法来使用 Java 中的“列表”中的元素对该地图进行排序吗?此外,如果您认为这种数据结构选择不好,请随时建议一种更简单的数据结构来执行此操作。

谢谢。

【问题讨论】:

  • 地图是个坏主意,我对您提供的链接中的答案投了反对票。列表列表是这里的方法。
  • 注意:当您比较字符串时,"100" &lt; "2"'1' &lt; '2' 如果您想要不同的行为,您需要更改比较器。
  • @AlexWien 你能解释一下原因吗?是因为我们不能轻松地对 Map 进行排序吗?
  • 列表答案列表将起作用,但您需要确保为每一列而不是每一行创建一个列表,以便排序工作。您的示例显示了包含每行数据的列表。读取 CSV 文件时有点棘手,但还不错。
  • 一个 csv 文件是一个没有键的行序列。 ArrayList 是完美的选择,它可以通过给出 position = linenumber 直接访问行。地图需要更多时间来查找行,以搜索关键行号。地图用于其他目的。

标签: java sorting csv map


【解决方案1】:

在 Java 8 中你可以这样做

SortedMap<Integer, List<String>> collect = Files.lines(Paths.get(filename))
    .collect(Collectors.groupingBy(
                                l -> Integer.valueOf(l.split(",", 4)[2]), 
                                TreeMap::new, Collectors.toList()));

注意:将数字作为字符串进行比较是个坏主意,因为 "100" &lt; "2" 可能不是您所期望的。

我会使用排序的多图。如果你手边没有一个,你可以这样做。

SortedMap<Integer, List<String>> linesByKey = new TreeMap<>();

public void addLine(String line) {
    Integer key = Integer.valueOf(line.split(",", 4));
    List<String> lines = linesByKey.get(key);
    if (lines == null)
         linesByKey.put(key, lines = new ArrayList<>());
    lines.add(line);
}

这将产生一个行集合,按数字排序,其中重复数字的行具有保留的顺序。例如如果所有行的编号相同,则顺序不变。

【讨论】:

  • Files.lines() 必须在资源 try(Stream&lt;String&gt; lines = Files.lines(Paths.get(filePath))) 中声明
【解决方案2】:

我会使用ArrayListArrayListString

ArrayList<ArrayList<String>>

每个条目是一行,它是一个字符串列表。 您通过以下方式初始化列表:

List<ArrayList<String>> csvLines = new ArrayList<ArrayList<String>>();

获取第 n 行:

List<String> line = csvLines.get(n);

为了排序,您编写了一个自定义比较器。在该比较器的构造函数中,您可以传递用于排序的字段位置。

compare 方法然后获取存储位置的字符串值,并根据位置将其转换为原始 ava 类型。例如,您知道在 csv 中的位置 2 处有一个 Integer,然后将 String 转换为 int。这是正确排序所必需的。您还可以将 Class 的 ArrayList 传递给构造函数,以便它知道哪个字段是什么类型。
然后根据列位置等使用String.compareTo()Integer.compare()

编辑工作代码示例:

List<ArrayList<String>> csvLines = new ArrayList<ArrayList<String>>();
Comparator<ArrayList<String>> comp = new Comparator<ArrayList<String>>() {
    public int compare(ArrayList<String> csvLine1, ArrayList<String> csvLine2) {
        // TODO here convert to Integer depending on field.
        // example is for numeric field 2
        return Integer.valueOf(csvLine1.get(2)).compareTo(Integer.valueOf(csvLine2.get(2)));
    }
};
Collections.sort(csvLines, comp);

【讨论】:

  • 编辑并更改了比较以使用数字。
  • 我对此很陌生,所以当我尝试您的代码时,Eclipse 将其指出为类型不匹配错误,提示“将 csvLines 的类型更改为 List>”。如果我做得对,你能告诉我吗?
  • 啊对,用List = new ArrayList>,这是java的弱点
  • 我试图将 List> 类型的 'csvLines' 传递给 'Collections.sort()' 但由于 sort 只接受 List 而不是 List>作为它的论点之一。你能帮我怎么做吗?
  • sort 接受要排序的列表和comparator.so Collections.sort(csvLines, MyCustomComparator);
【解决方案3】:

您还可以使用列表列表:

List<List<String>> Llp = new ArrayList<List<String>>();

然后你需要调用 sort 扩展一个自定义比较器来比较列表中的第三项:

    Collections.sort(Llp, new Comparator<LinkedList<String>>() {
            @Override
            public int compare(LinkedList<String> o1, LinkedList<String> o2) {
                try {                      
                    return o1.get(2).compareTo(o2.get(2));
                } catch (IndexOutOfBoundsException e) {
                    return 0;
                }
 }

【讨论】:

  • 捕获 NPE 通常不是一个好主意,尤其是从文件中读取字符串时不可能发生这种情况。
  • CSV 文件可能因任何原因而丢失数据,因此可能会创建一个仅包含 2 个元素的列表。
  • 所以你可以得到一个 IndexOutOfBoundsException ?
  • 将数值排序为字符串将导致"10" 被放置在"2" 之前。编辑,啊,我看到彼得已经提到这一点作为对该问题的评论,但我认为这里也值得一提......
  • @lolkidoki 'Collections.sort()' 不能接受 'Llp' 作为参数,因为 'Llp' 是一个列表列表,而有效参数只是一个列表。如果我错了,请您纠正我吗?
【解决方案4】:

在下面的代码中,我根据第二列对 CSV 文件进行了排序。


public static void main(String[] args) throws IOException {
    String csvFile = "file_1.csv";
    String line = "";
    String cvsSplitBy = ",";
    List<List<String>> llp = new ArrayList<>();
    try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
        while ((line = br.readLine()) != null) {
            llp.add(Arrays.asList(line.split(cvsSplitBy)));
        }
        llp.sort(new Comparator<List<String>>() {
            @Override
            public int compare(List<String> o1, List<String> o2) {
                return o1.get(1).compareTo(o2.get(1));
            }
        });
        System.out.println(llp);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-21
    • 2020-09-06
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 2012-06-20
    相关资源
    最近更新 更多