Эффективно сделать представление (или скопировать) подмножество большой HashMap в Kotlin - PullRequest
0 голосов
/ 13 декабря 2018

Я пытаюсь создать подхеш-карту из огромного хеш-карты без копирования оригинального.

В настоящее время я использую это:

val map = hashMapOf<Job, Int>()
val copy = HashMap(map)
listToRemoveFromCopy.forEach { copy.remove(it) }

это стоило мне около 50% моего текущего алгоритма,Потому что Java очень часто вычисляет хеш job.Мне нужна только map минус listToRemoveFromCopy в новой переменной без удаления элементов listToRemoveFromCopy из исходного списка.

кто-нибудь знает это?

Спасибо за помощь

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

В дополнение к прямому ответу Акселя:

Можно ли оптимизировать расчет хэш-кода задания?Если расчет не может быть ускорен, может ли он кэшировать результат?(Для этого есть достаточно прецедентов, включая java.lang.String.) Или, если класс не находится под вашим контролем, вы можете создать делегат / оболочку, которая переопределяет вычисление хэш-кода?

0 голосов
/ 14 декабря 2018

Во-первых, вам необходимо кэшировать хеш-код для Job, потому что любой подход, который вы используете, будет неэффективным, если у вас не будет набора или карты Job объектов, которые работают на максимальной скорости.

Надеемся, что части, которые делают его хеш-кодом, являются неизменяемыми, в противном случае его не следует использовать в качестве ключа. очень опасно изменять ключ хэш-код / ​​равно во время использования на карте или в наборе.Вы должны кэшировать его при первом вызове hashCode(), чтобы не понести расходы до тех пор, пока вы не будете уверены, что она вам всегда понадобится.

Затем измените listToRemoveFromCopy на Set, такэто может быть эффективно использовано многими способами.Вы должны сделать предыдущий шаг до этого.

Теперь у вас есть несколько вариантов.Наиболее эффективным является:

Гуава имеет служебную функцию Maps.filterKeys, которая возвращает вид на карту, и выможет создать предикат, который работает против Set элементов для удаления.

 val removeKeys = listToRemoveFromCopy.toSet()
 val mapView = Maps.filterKeys(map, Predicates.not(Predicates.in(removeKeys)))

Но обратите внимание, что некоторые методы в представлении не очень эффективны.Если вы избегаете этих методов, это будет наиболее эффективный вариант:

Многие из методов отфильтрованной карты, такие как size (), выполняют итерацию для каждого сопоставления ключ / значение в базовой карте и определяют, какиеудовлетворить фильтр.Когда просмотр в реальном времени не требуется, может быть быстрее скопировать отфильтрованную карту и использовать копию.

Если вам нужно сделать копию вместо этого, у вас есть несколько подходов:

Используйте filterKeys на карте, чтобы создать новую карту за один выстрел.Это хорошо, если список удаления может составлять больший процент от общего количества ключей.

val removeKeys = listToRemoveFromCopy.toSet()
val newMap = map.filterKeys { it !in removeKeys }

Еще одна заманчивая опция, с которой вам следует быть осторожным, это оператор минус -, который копирует полную карту, а затем удаляет элементы.Он может использовать listToRemoveFromCopy как есть, не будучи набором, но полная копия карты может отменить преимущество.Так что не делайте этого, пока список удаления не представляет собой небольшой процент ключей.

val newMapButSlower = map - listToRemoveFromCopy

Вы можете выбрать одну модель поверх другой в зависимости от соотношения между размером карты и размером списка удаления, найти точку разрыва, котораяработает для вашего "огромного".

Реализация собственного представления на карте, чтобы избежать копирования, возможна , но не тривиально (и под этим я подразумеваю очень сложный ).Каждый переопределяемый вами метод должен все время работать правильно (включая собственные hashCode и equals карты), и другие представления должны создаваться вокруг набора ключей и значений.entrySet было бы противно получить права.Я бы искал заранее написанное решение, прежде чем пытаться самостоятельно (Гуава выше или другое).Эта модель нулевого копирования была бы наиболее эффективным решением, но большей частью кода, и это то, что я сделал бы в том же случае, если бы «огромный» означал значительное время обработки.С этим подходом можно многое ошибиться, если вы неправильно поймете какую-либо часть контракта на реализацию.

Вы можете обернуть решение Guava тем, которое поддерживает атрибут size, поскольку элементы манипулируют и, следовательно, будут эффективны для этого случая.Вы также можете написать более эффективное решение, если знаете, что исходная карта доступна только для чтения.Для идей, ознакомьтесь с реализацией Guava FilteredKeyMap и его предка AbstractFilteredMap .

В итоге, вероятно, кеширование вашего хеш-кода происходитчтобы дать вам самый большой результат для усилий.Начни там.Это понадобится вам даже для подхода с использованием гуавы.

0 голосов
/ 13 декабря 2018

Вы можете использовать функцию filterKeys.Карта будет повторяться только один раз

val copy = map.filterKeys { it !in listToRemoveFromCopy }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...