在Java中对文本文件进行排序的最佳方法

时间:2009-07-07 16:48:09

标签: java sorting

我有一个CSV文件,我正在使用opencsv库进行处理。所以我可以阅读每一行。我需要做的特定转换要求我在使用java文件的主要部分运行之前先对该文件进行排序。

e.g。

5423, blah2, blah
5323, blah3, blah
5423, blah4, blah
5444, blah5, blah
5423, blah6, blah

应该成为

5323, blah3, blah
5423, blah2, blah
5423, blah4, blah
5423, blah6, blah
5444, blah5, blah

等。

我需要这样做的原因是我将具有相同id的所有行组合并将它们输出到新文件。

有什么问题:

  1. 使用opencsv库

  2. 读取csv的每一行
  3. 将它们添加到二维数组

  4. 在此

  5. 上运行某种排序
  6. 循环排序数组并输出到文件。

  7. 关于此的任何其他想法以及对数据进行排序的最佳方法是什么?

    我的Java上有点生锈。

    更新: 澄清最终输出

    看起来像是:

    5323, blah3, blah
    5423, blah2!!blah4!!blah6, blah
    5444, blah5, blah
    

    这是我正在做的非常简化的版本。实际上,JBase系统中的多选项字段需要它。这是请求的文件格式。

    原始文件中有超过100,000行。

    这将不止一次运行,它的运行速度对我很重要。

7 个答案:

答案 0 :(得分:5)

要完成最新请求,我强烈建议您在google集合中使用Multimap。您的代码如下:

CSVReader reader = ...;
CSVWriter writer = ...;

Multimap<String, String> results = TreeMultimap.create();

// read the file
String[] line;
for ((line = reader.readNext()) != null) {
    results.put(line[0], line[1]);
}

// output the file
Map<String, Collection<String>> mapView = results.asMap();
for (Map.Entry<String, Collection<String> entry : mapView.entries()) {
    String[] nextLine = new String[2];
    nextLine[0] = entry.getKey();
    nextLine[1] = formatCollection(entry.getValue());
    writer.writeNext(nextLine);
}

您需要使用"blah\n"作为线路编号。如果您关心速度,而不是关注条目的排序,那么您也应该对HashMultimap进行基准测试。

我之前的回答

最直接的方法是在* nix中使用sort命令(例如Linux和Mac OS),例如

sort -n myfile.csv

Windows也有一个sort命令,但会按字母顺序对行进行排序(即“5”,将放在“13”行之前)。

但是,建议的解决方案没有任何问题。您也可以使用TreeSet

,而不是构建数组并对其进行排序

编辑:添加关于Windows的说明。

答案 1 :(得分:1)

您是否尝试过使用Collections.sort()Comparator个实例?

答案 2 :(得分:1)

如果您只对id的排序感兴趣,并且不关心该id中的排序,您可以简单地将Commons Collections中的MultiValueMap与TreeMap结合起来:

MultiValueMap m = MultiValueMap.decorate(new TreeMap());

m.put(2, "B");
m.put(3, "Y");
m.put(1, "F");
m.put(1, "E");
m.put(2, "K");
m.put(4, "Q");
m.put(3, "I");
m.put(1, "X");

for(Iterator iter = m.entrySet().iterator(); iter.hasNext(); ) {
    final Map.Entry entry = (Map.Entry)iter.next();
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

运行此命令:

1: [F, E, X]
2: [B, K]
3: [Y, I]
4: [Q]

有一个重载的decorate方法,它允许您指定要在MultiValueMap中使用的集合类型。如果您需要在ID中进行排序,则可以对此执行某些操作。

答案 3 :(得分:0)

您可以使用单个维度的ArrayList(或其他集合),并使用Collections排序方法对Java进行排序。你描述的其他所有内容听起来都非常标准。

答案 4 :(得分:0)

您说您需要“排序”这些项目,但您的说明听起来好像需要分组它们。这可以通过多种方式完成;您可能希望查看多个地图,例如google collections提供的地图;或者你可以简单地创建一个

HashMap<Long, List<String>>

并在阅读时将每一行放入相关列表中。我喜欢这样的情况是两次遍历文件,一次向每个键添加一个新的ArrayList,第二次将每个字符串添加到列表中,但是使用单个pass可能更有效(只是不那么简单) ,其中您检查列表是否已经在地图中。

答案 5 :(得分:0)

听起来你不需要对整个事情进行排序。我不确定你会有多少行,但似乎你可以使用某种基于散列的方案。您可以将文件视为散列映射中的存储桶,并在读取每一行后,确定它属于哪个文件。然后,您可以进一步处理每个文件。有几种方法可以做到这一点。

  • 如果您没有很多“密钥”,您实际上可以将所有密钥保存在内存中作为密钥在string =&gt;的哈希映射中string(将键映射到该行所属的文件名的映射)。

  • 如果有太多可能的密钥留在内存中。您可以尝试将行存储到不同的文件中,以帮助减小文件的大小。然后,您可以将每个文件保留在内存中,这样您就可以将行转储到集合中并进行排序。或者可能使用我提到的第一个方案。

这有意义吗?如果你感到困惑,我可以详细说明。我想你的密钥将通过某种方式组合你的csv行的所有列。

如果您的文件变得非常大,这种方法将更具可扩展性。您不希望依赖于将整个文件放在内存中,并且排序需要O(nlogn)时间,而理论上,散列方案只是O(n)。

答案 6 :(得分:0)

FlatPack非常适合阅读这样的文件并对其进行排序。它还具有将数据集导出到文件的选项。