Подтвердить что ты не робот

Удалить дубликаты из большого целочисленного массива с помощью Java

Знаете ли вы сколько-нибудь эффективный способ удаления дублированных значений из очень большого целочисленного массива с помощью Java? Размер массива зависит от зарегистрированного пользователя, но всегда будет превышать 1500000 несортированных значений с некоторыми дубликатами. Каждое целое число содержит число от 100000 до 9999999.

Я попытался преобразовать его в список, но куча на моем сервере не позволяет этот объем данных (мой интернет-провайдер ограничил его). А регулярный цикл цикла в цикле for занимает более 5 минут для вычисления.

Размер массива без дубликатов - это тот, который я буду хранить в моей базе данных.

Помощь будет оценена!

4b9b3361

Ответ 1

Возможно, вы можете использовать бит-набор? Я не знаю, насколько эффективен Java BitSet. Но 9999999 возможных значений будет принимать только 9999999/8 = 1250000 bytes = чуть более 1Mb. Когда вы проходите массив значений, установите соответствующий бит в значение true. Затем вы можете пройти через бит и вывести соответствующее значение всякий раз, когда бит бит установлен в true.

1Mb будет входить в кеш процессора, поэтому это может быть довольно эффективным в зависимости от реализации набора бит.

Это также имеет побочный эффект для сортировки данных.

И... это алгоритм O (n), так как он требует одного прохода над входными данными, заданными операциями являются O (1) (для набора на основе массива, подобного этому), а выходной проход - также O (m), где m - количество уникальных значений и, по определению, должно быть <= n.

Ответ 2

Я бы сделал hashset, где я храню все значения, содержащиеся в списке, прежде чем я начну добавлять элементы в список. Затем просто проверьте, чтобы хешсет не содержал значение, которое вы хотите добавить.

Ответ 3

Set<Integer> set = new HashSet<Integer>();
Collections.addAll(set, array);

вам нужен массив Integer[] вместо int[].

Ответ 4

Сначала попробуйте отсортировать массив:

int arr[] = yourarray;
Arrays.sort(arr);
// then iterate arr and remove duplicates

Ответ 5

int[] a;
Arrays.sort(a);
int j = 0;
for (int i = 1; i < a.length; ++i) {
  if (a[i] != a[j]) {
    ++j;
    a[j] = a[i];
  }
}
// now store the elements from 0 to j (inclusive - i think)

Ответ 6

Истинно отчаянный может записать массив на диск и отключить sort | uniq | wc -l <infile.txt и захватить вывод. Это было бы необходимо, если бы память была еще слишком плотной или объемное пространство целых чисел стало больше. Мне это не нравится (он даже работает unix!), Но я хочу сказать, что есть много способов выполнить задачу.

Другое наблюдение заключается в том, что минимальное значение составляет 100 000. Таким образом, мы могли бы вычесть 100 000 из максимального значения 9999,999, уменьшив пространство в пространстве и, таким образом, сохранив некоторую память. Возможно, 100k/8 бит - это арахис в схеме вещей, но он по существу свободен для этого.

Ответ 7

Возможно, вы могли бы сделать несколько проходов над данными? Например, если вы сделали десять проходов над данными и применили одно из приведенных выше предложений к меньшему подмножеству данных (скажем, когда значение mod pass # == 0). Таким образом:

for (int i = 0 to 9) {
  set = new Set()
  for (each entry in the data set) {
    if (entry % i == 0) {
      set.add(entry)
    }
  }
  output set
}

Таким образом, вы будете торговать временем для памяти (увеличьте количество проходов за меньшую память/больше времени и наоборот).

Ответ 8

Может быть, хеш-набор, который работает с примитивами, а не объекты, выполнит эту работу? Существуют бесплатные реализации (ранее они не использовались, но, возможно, это работает):

http://trove4j.sourceforge.net/

http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntHashSet.html

Тогда будет выглядеть:

int[] newArray = new TIntHashSet(yourArray).toArray();

Ответ 9

Если вы уверены, что целые числа имеют резонансные небольшие значения (например, всегда больше нуля и меньше 1000 или 10000), вы можете попробовать трюк, подобный этому:

    final int MAX = 100; 
    int[] arrayWithRepeats = {99, 0, 10, 99, 0, 11, 99};

    //we are counting here integers with the same value
    int [] arrayOfValues = new int[MAX+1];
    int countOfUniqueIntegers = 0;
    for(int i : arrayWithRepeats) {
        if(arrayOfValues[i] == 0) {
            countOfUniqueIntegers++;
        }
        arrayOfValues[i]++;
    }

    // you can use arrayOfValues (smaller) or convert it
    // to table of unique values (more usable)

    int[] arrayOfUniqueValues = new int[countOfUniqueIntegers];
    int index = 0;
    for(int i = 0; i<arrayOfValues.length; i++) {
        if(arrayOfValues[i] != 0) {
            arrayOfUniqueValues[index] = i;
            index++;
        }
    }

    //and now arrayOfUniqueValues is even sorted
    System.out.println( Arrays.toString(arrayOfUniqueValues) );

Выход: [0, 10, 11, 99]