Какой самый быстрый способ удалить элемент из карты по значению в Java?

Это точно правильно, потому что компилятор должен знать, какой тип он предназначен для распределения. Поэтому классы шаблонов, функции, перечисления и т. Д. Должны быть реализованы также в файле заголовка, если он должен быть опубликован или частично из библиотеки (статический или динамический), поскольку файлы заголовков НЕ скомпилированы в отличие от файлов c / cpp, которые находятся. Если компилятор не знает, что тип не может его скомпилировать. В .Net это возможно, потому что все объекты происходят из класса Object. Это не .Net.

34
задан Supertux 26 August 2009 в 16:23
поделиться

11 ответов

Без использования двунаправленной карты ( commons-collections и google collections они есть), вы застряли с повторением карты

26
ответ дан 27 November 2019 в 06:20
поделиться

Если у вас нет обратной карты, я бы выбрал итератор.

DomainObj valueToRemove = new DomainObj();

for (
    Iterator<Map.Entry<String, DomainObj>> iter = map.entrySet().iterator();
    iter.hasNext();
) {
    Map.Entry<String, DomainObj> entry = iter.next();
    if (valueToRemove.equals(entry.getValue())) {
        iter.remove();
        break; // if only want to remove first match.
    }
}
11
ответ дан 27 November 2019 в 06:20
поделиться

Вы всегда можете использовать коллекцию значений, поскольку любые изменения, внесенные в эту коллекцию, приведут к тому, что изменение будет отражено на карте. Так что, если бы вы вызывали Map.values ​​(). Remove (valueToRemove), это должно сработать, хотя я не уверен, что вы увидите производительность лучше, чем та, которая у вас есть с этим циклом. Одна из идей - расширить или переопределить класс карты таким образом, чтобы фоновая коллекция всегда сортировалась по значению - это позволило бы вам выполнять двоичный поиск по значению, который может быть быстрее.

Изменить: это по сути то же самое как ответ Alcon, за исключением того, что я не думаю, что он будет работать, поскольку entrySet по-прежнему будет упорядочиваться по ключу - и в этом случае вы не можете вызвать .remove () со значением.

7
ответ дан 27 November 2019 в 06:20
поделиться

Я бы использовал эту

 Map x = new HashMap();
x.put(1, "value1");
x.put(2, "value2");
x.put(3, "value3");
x.put(4, "value4");
x.put(5, "value5");
x.put(6, "value6");

x.values().remove("value4");

правку: потому что на объекты ссылаются «указатели», а не по значению.

N

6
ответ дан 27 November 2019 в 06:20
поделиться

Если у вас нет возможности определить ключ из DomainObj, я не вижу, как вы можете это улучшить. Нет встроенного метода для получения ключа из значения, поэтому у вас есть для итерации по карте.

Если это то, что вы делаете постоянно, вы можете поддерживать две карты (строка -> DomainObj и DomainObj-> Key).

4
ответ дан 27 November 2019 в 06:20
поделиться

Как говорилось в большинстве других плакатов, это обычно операция O (N), потому что вам придется просматривать весь список значений хеш-таблицы, несмотря ни на что. @tackline предлагает правильное решение для сохранения использования памяти на уровне O (1) (я дал ему за это голосование)

Другой вариант - пожертвовать пространством памяти ради скорости. Если ваша карта имеет разумный размер, вы можете хранить две карты параллельно.

Если у вас есть карта, поддерживайте карту параллельно ей. Когда вы вставляете / удаляете на одной карте, проделайте то же самое и с другой. Конечно, это уродливо, потому что вы тратите впустую место, и вам нужно будет убедиться, что метод hashCode для DomainObj написан правильно, но время удаления падает с O (N) до O (1), потому что вы можете найти ключ / отображение объекта в постоянное время в любом направлении. Приложение: По сути, это то, что предложил @msaeed, просто без сторонней библиотеки.

2
ответ дан 27 November 2019 в 06:20
поделиться

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

Итак, что я бы сделал, так это делегировал другому объекту ответственность за поддержание ссылки на объекты, добавленные к этой карте.

Итак, в следующий раз, когда вам нужно будет удалить ее, вы воспользуетесь этой «обратной картой». ..

 class MapHolder { 

     private Map<String, DomainObj> originalMap;
     private Map<DomainObj,String> reverseMap;

     public void remove( DomainObj value ) {
           if ( reverseMap.contains( value ) ) { 
                 originalMap.remove( reverseMap.get( value ) );
                 reverseMap.remove( value );
           }
     }
  }

Это намного быстрее, чем повторение.

Очевидно, вам нужно поддерживать их синхронизацию. Но это не должно быть так сложно, если вы настроите свой код так, чтобы один объект отвечал за состояние карты.

Помните, что в ООП есть объекты, у которых есть состояние и поведение. Если ваши данные передают переменные повсюду, вы создаете ненужные зависимости между объектами

Да, вам потребуется некоторое время, чтобы исправить код, но время, потраченное на его исправление, избавит вас от головной боли в будущем. Думаю об этом.

0
ответ дан 27 November 2019 в 06:20
поделиться

Вот однострочное решение:

map.values().remove(valueToRemove);

Это, вероятно, быстрее, чем определение собственного итератора, поскольку код коллекции JDK был значительно оптимизирован.

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

24
ответ дан 27 November 2019 в 06:20
поделиться

Более короткое использование итератора - это использовать итератор values ​​().

DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
        if (valueToRemove.equals(it.next())) {
                it.remove();
                break;
        }
}
2
ответ дан 27 November 2019 в 06:20
поделиться

Мы знаем, что такая ситуация возникает редко, но она чрезвычайно полезна. Я предпочитаю BidiMap из org.apache.commons.collections .

1
ответ дан 27 November 2019 в 06:20
поделиться

Правильным и быстрым однострочным предложением будет:

while (map.values().remove(valueObject));

Странно, что в большинстве примеров выше предполагается, что valueObject уникален.

73
ответ дан 27 November 2019 в 06:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: