ПРОБЛЕМА
У меня есть список массивов, и я хочу подсчитать вхождения дубликатов.
Например, если у меня есть это:
{{1,2,3},
{1,0,3},
{1,2,3},
{5,2,6},
{5,2,6},
{5,2,6}}
Мне нужна карта (или любая соответствующая коллекция), подобная этой:
{ {1,2,3} -> 2,
{1,0,3} -> 1,
{5,2,6} -> 3 }
Я могу даже потерять значения массивов, меня интересуют только кардиналы (например, 2, 1 и 3 здесь).
МОЕ РЕШЕНИЕ
Я использую следующий алгоритм:
Сначала хешируем массивы и проверяем каждый хешнаходится в HashMap<Integer, ArrayList<int[]>>
, назовем его diverHash , где ключом является хеш, а значением является ArrayList, назовем его rowList , содержащим различные массивы для этого хеша (чтобы избежать коллизий).
Если хеш не находится в diverHash , поместите его со значением 1 в другой HashMap<int[], Long>
, который считает каждое вхождение, давайте назовем его differentElements .
Тогда, если хеш находится в diverHash , проверьте, соответствует ли соответствующий массив is содержится в rowList .Если это так, увеличьте значение в differentElements , связанное с идентичным массивом, найденным в rowList .(Если вы используете новый массив в качестве ключа, вы создадите другой ключ, поскольку их ссылки различны).
Вот код, возвращаемый логическим значением, сообщает, был ли найден новый отдельный массивЯ последовательно применяю эту функцию ко всем моим массивам:
HashMap<int[], Long> distinctElements;
HashMap<Integer, ArrayList<int[]>> distinctHash;
private boolean addRow(int[] row) {
if (distinctHash.containsKey(hash)) {
int[] indexRow = distinctHash.get(hash).get(0);
for (int[] previousRow: distinctHash.get(hash)) {
if (Arrays.equals(previousRow, row)) {
distinctElements.put(
indexRow,
distinctElements.get(indexRow) + 1
);
return false;
}
}
distinctElements.put(row, 1L);
ArrayList<int[]> rowList = distinctHash.get(hash);
rowList.add(row);
distinctHash.put(hash, rowList);
return true;
} else {
distinctElements.put(row, 1L);
ArrayList<int[]> newValue = new ArrayList<>();
newValue.add(row);
distinctHash.put(hash, newValue);
return true;
}
}
ВОПРОС
Проблема в том, что мой алгоритм слишком медленный для моих потребностей (40 с для 5 000 000и 2h-3h для 20 000 000 массивов).Профилирование с помощью NetBeans говорит мне, что хеширование занимает 70% времени выполнения (с использованием хеш-функции Google Guava murmur3_128).
Есть ли другой алгоритм, который мог бы быть быстрее?Как я уже сказал, меня не интересуют значения массивов, а только количество их вхождений.Я готов пожертвовать точностью ради скорости, чтобы с вероятностным алгоритмом все было в порядке.