Строчные все ключи HashMap
Я столкнулся со сценарием, в котором я хочу прописать все ключи HashMap в нижнем регистре (не спрашивайте почему, я просто должен это сделать). HashMap имеет несколько миллионов записей.
Сначала я подумал, что просто создам новую карту, перебираю записи карты, которая должна быть в нижнем регистре, и добавляю соответствующие значения. Эта задача должна выполняться только один раз в день или что-то в этом роде, поэтому я подумал, что смогу выдержать это.
Map<String, Long> lowerCaseMap = new HashMap<>(myMap.size());
for (Map.Entry<String, Long> entry : myMap.entrySet()) {
lowerCaseMap.put(entry.getKey().toLowerCase(), entry.getValue());
}
это, однако, вызвало некоторые ошибки OutOfMemory, когда мой сервер был перегружен в то время, когда я собирался скопировать карту.
Теперь мой вопрос: как я могу выполнить эту задачу с наименьшим объемом памяти?
Будет ли удаление каждой клавиши после нижнего регистра - добавлено ли в новую карту помощь?
Могу ли я использовать потоки Java8, чтобы сделать это быстрее? (например, что-то вроде этого)
Map<String, Long> lowerCaseMap = myMap.entrySet().parallelStream().collect(Collectors.toMap(entry -> entry.getKey().toLowerCase(), Map.Entry::getValue));
Обновление Кажется, что это Collections.unmodifiableMap
так что у меня нет возможности
удаление каждого ключа после нижнего регистра - добавлено на новую карту
4 ответа
Вместо того, чтобы использовать HashMap
, вы можете попробовать использовать TreeMap
с учетом регистра без учета регистра. Это позволит избежать необходимости создавать строчную версию каждого ключа:
Map<String, Long> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
map.putAll(myMap);
Как только вы создали эту карту, put()
а также get()
будет вести себя без учета регистра, поэтому вы можете сохранять и извлекать значения, используя строчные клавиши. Перебор ключей вернет их в исходном, возможно, в верхнем регистре.
Вот несколько похожих вопросов:
Вы не можете удалить запись во время итерации по карте. Если вы попытаетесь это сделать, у вас будет исключение ConcurentModificationException.
Так как проблема заключается в OutOfMemoryError, а не в ошибке производительности, использование параллельного потока также не поможет.
Несмотря на то, что в последнее время некоторые задачи в Stream API будут выполнены, это все равно приведет к тому, что в какой-то момент в памяти появятся две карты, поэтому проблема все равно останется.
Чтобы обойти это, я видел только два пути:
- Дайте больше памяти вашему процессу (увеличивая -Xmx в командной строке Java). Память дешева в эти дни;)
- Разделите карту и работайте на куски: например, вы делите размер карты на десять и обрабатываете один кусочек за раз и удаляете обработанные записи перед обработкой нового кусочка. Таким образом, вместо того, чтобы иметь два раза карту в памяти, у вас будет только 1,1 раза карта.
Для алгоритма разделения вы можете попробовать что-то вроде этого, используя Stream API:
Map<String, String> toMap = new HashMap<>();
int chunk = fromMap.size() / 10;
for(int i = 1; i<= 10; i++){
//process the chunk
List<Entry<String, String>> subEntries = fromMap.entrySet().stream().limit(chunk)
.collect(Collectors.toList());
for(Entry<String, String> entry : subEntries){
toMap.put(entry.getKey().toLowerCase(), entry.getValue());
fromMap.remove(entry.getKey());
}
}
Проблемы в приведенных выше ответах верны, и вам может потребоваться пересмотреть изменение структуры данных, которую вы используете.
для меня у меня была простая карта, мне нужно было изменить ее клавиши на нижний регистр
взгляните на мой фрагмент, это тривиальное решение и плохая производительность
private void convertAllFilterKeysToLowerCase() {
HashSet keysToRemove = new HashSet();
getFilters().keySet().forEach(o -> {
if(!o.equals(((String) o).toLowerCase()))
keysToRemove.add(o);
});
keysToRemove.forEach(o -> getFilters().put(((String) o).toLowerCase(), getFilters().remove(o)));
}
Насчет объема памяти не уверен. Если вы используете Kotlin, вы можете попробовать следующее.
val lowerCaseMap = myMap.mapKeys { it.key.toLowerCase() }
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map-keys.html