2

我的工作区中保存了 4 个文件 a、b、c、d 中的一堆 id。我想将所有这些 id 按排序顺序合并到一个文件merged.txt 中。它们将每行保存一个作为字符串。我可以通过将文件放入内存来单独对文件进行排序。但是如何合并它们,可能会有重复的条目。我想不出如何比较四个文件中的每个条目(它们可以增长到 8,所以不能硬编码)。特别是如何比较条目以及如何仅推进那些最小的文件指针?

public void sortFile() throws IOException
{
    File a = new File("/Users/phoenix/workspace/data/a.txt");
    File b = new File("/Users/phoenix/workspace/data/b.txt");
    File c = new File("/Users/phoenix/workspace/data/c.txt");
    File d = new File("/Users/phoenix/workspace/data/d.txt");

    doSort(a);
    doSort(b);
    doSort(c);
    doSort(d);

    merge();
}

如何根据下面的伪代码修改合并方法?

public void merge()
{
    File dir = new File("/Users/phoenix/workspace/data");

    for(File f: dir.listFiles())
    {
        // toDo: merge into a single file merged.txt
    }
}

public void doSort(File f) throws IOException
{
    BufferedReader reader = new BufferedReader(new FileReader(f));
    String line;
    ArrayList<String> list = new ArrayList<String>();
    while((line = reader.readLine())!=null)
    {
        list.add(line);
    }

    Collections.sort(list);

    PrintWriter out = new PrintWriter(f);

    for(String s:list)
    out.println(s);

    reader.close();
    out.close();
}


    public void merge() throws IOException
    {
        File dir = new File("/Users/phoenix/workspace/data");
        File merged = new File("/Users/phoenix/workspace/data/merged.txt");

        ArrayList<BufferedReader> readers = new ArrayList<BufferedReader>(dir.listFiles().length);
        ArrayList<String> list = new ArrayList<String>();
        PrintWriter out = new PrintWriter(merged);

        for(File f: dir.listFiles())
        {
            readers.add(new BufferedReader(new FileReader(f)));
        }

        while(true)
        {
        for (BufferedReader reader: readers)
        {
            if(reader.readLine()!=null)
                list.add(reader.readLine());

            else
            {
                reader.close();
            }

        }

        String min = Collections.min(list);
        int index = list.indexOf(min);
        out.write(min);
    }



 }
4

3 回答 3

2

您是在寻找解决问题,还是在 Java 中解决问题。

如果您只是在寻找执行此操作的方法,并且可以访问终端,并且“排序”是指按字母顺序排序,那么您可以更简单地进行操作。

cat "/Users/phoenix/workspace/data/a.txt" "/Users/phoenix/workspace/data/b.txt" "/Users/phoenix/workspace/data/c.txt" "/Users/phoenix/workspace/data/d.txt"|sort > merged.txt

用于排序并仅拾取 uniq 的

cat "/Users/phoenix/workspace/data/a.txt" "/Users/phoenix/workspace/data/b.txt" "/Users/phoenix/workspace/data/c.txt" "/Users/phoenix/workspace/data/d.txt"|sort |uniq > merged.txt

更新:顺便说一句,要按数字排序,请使用

sort -n
于 2013-06-11T03:07:03.217 回答
1

以下是该算法的一般描述:

  1. 打开每个文件,并阅读其第一项。
  2. 遍历所有文件,选择当前项最小的一个文件;如果多个文件具有相同的项目,则选择具有该项目的第一个文件
  3. 从您在步骤 2 中确定的文件中删除最小的项目,并将其写入输出文件
  4. 如果您从中删除项目的文件已结束,请关闭该文件,然后将其从文件列表中删除
  5. 如果文件列表不为空,则返回步骤 2。

在执行算法之前,您的代码需要检查是否存在至少一个输入文件;否则,您的代码应该退出。

编辑:您的merge代码看起来不像上面的算法;这里有一些代码可以帮助您入门:

// Prepare your readers and their top items
for(File f: dir.listFiles()) {
    BufferedReader br = new BufferedReader(new FileReader(f));
    String firstLine = reader.readLine();
    // Your code inserts buffered readers unconditionally;
    // You should not insert readers for empty files.
    if (firstLine != null) {
        readers.add(br);
        list.add(firstLine);
    } else {
        br.close();
    }
}
// Stop when the last reader is removed
while (!readers.isEmpty()) {
    int minIndex = ... // Find the index of the smallest item in the "list"
    out.write(list.get(minIndex));
    BufferedReader br = readers.get(minIndex);
    String next = br.readLine();
    if (next != null) {
        list.set(minIndex, next);
    } else {
        br.close();
        list.remove(minIndex);
        readers.remove(minIndex);
    }
}
于 2013-06-11T02:37:16.250 回答
0

将每个文件读入列表

List<String> list1 = Files.readAllLines(Path.get(path), StandardCharsets.UTF_8);
...

将列表1合并到一个列表中

List<String> list = new ArrayList<>();
list.addAll(list1);
...

现在对行进行排序

Collections.sort(list);

并将它们写入单个文件。

注意:如果您不想重复行,请使用 TreeSet 而不是 ArrayList

于 2013-06-11T03:01:09.190 回答