Объединение нескольких отсортированных CSV-файлов со сложным сравнением - PullRequest
1 голос
/ 21 декабря 2011

У меня есть список отсортированных, CSV, файлов, которые я хочу отсортировать и объединить в выходной файл.

Я не хочу делать простое сравнение строк, но сравнивать соответственно с картой типов, которые у меня есть для каждого значения, например:

Одна из строк:
1, 15.12.2011, Дэвид Рейвен, Нью-Йорк

В карте типов у меня есть это: первый столбец - длинная, вторая дата, третья строка, ...

Таким образом, компаратор должен сравнивать значения соответственно.

Как я могу сделать это с максимальной эффективностью?
PriorityQueue? TreeMap?

Я предпочитаю не использовать сторонние библиотеки или сортировщики.
Входной файл огромен.

Ответы [ 3 ]

1 голос
/ 21 декабря 2011

Создайте массив (или, если хотите, коллекцию) Readers / InputStreams, по одному для каждого CSV-файла.

По аналогии с идеей @JustinKSU, создайте TreeMap, где ключ - одна строка изфайл CSV.Передайте пользовательский компаратор, ваш собственный impl, который сортирует по длине, дате и т. Д. Значением является индекс (вероятно, целое число, который может быть именем файла, если ваша коллекция является картой) того файла в вашем массиве / коллекции.

Заполните TreeMap, прочитав первую строку из каждого файла.

Удалите нижнюю строку, используя TreeMap.pollFirstEntry (), и запишите ключ (строку) в Writer / OutputStream.Используйте значение, чтобы прочитать еще одну строку из соответствующего файла (проверка на EOF) и добавить ее в TreeMap.

Повторять до тех пор, пока TreeMap не станет пустым.Закройте все.

Редактировать - ниже добавлен исходный код

И обратите внимание, это работает, только если входные файлы уже отсортированы !(Как было указано в вопросе)

public void mergeSort(File[] inFiles, File outFile, Comparator<String> comparator) throws IOException  {

      try {
         BufferedReader[] readers = new BufferedReader[inFiles.length];
         PrintWriter writer = new PrintWriter(outFile);
         TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>(
               comparator);

         // read first line of each file. We don't check for EOF here, probably should
         for (int i = 0; i < inFiles.length; i++) {
            readers[i] = new BufferedReader(new FileReader(inFiles[i]));
            String line = readers[i].readLine();
            treeMap.put(line, Integer.valueOf(i));
         }

         while (!treeMap.isEmpty()) {
            Map.Entry<String, Integer> nextToGo = treeMap.pollFirstEntry();
            int fileIndex = nextToGo.getValue().intValue();
            writer.println(nextToGo.getKey());

            String line = readers[fileIndex].readLine();
            if (line != null)
               treeMap.put(line, Integer.valueOf(fileIndex));
         }
      }
      finally {
         // close everything here...
      }
   }
0 голосов
/ 21 декабря 2011

Один, может быть, немного неортодоксальный вариант - использовать оперативную базу данных, например, HSQLDB . Откройте базу данных где-нибудь во временном каталоге, где у вас достаточно места, создайте таблицу с необходимыми полями, вставьте все записи из всех CSV-файлов и, наконец, сделайте выборку из всех записей с соответствующим предложением ORDER BY, которое отражает желаемый порядок сортировки. и сохранить результаты, где вы хотите. Конечно, для этого потребуется немного дискового пространства, но это возможное решение, которое я использовал в прошлом для подобных проблем.

0 голосов
/ 21 декабря 2011

Если вы хотите сделать все это в памяти, я бы порекомендовал передать TreeSet в ваш Comparitor.Это было бы самой простой реализацией.Если вы не можете сохранить все это в памяти, вы можете открыть InputStreams для всех ваших файлов и выполнить цикл для каждого из них, пока не определите «самое низкое» значение и не выведете его в новый файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...