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

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

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

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

    DomainObj valueToRemove = new DomainObj();
    String removalKey = null;

    for (Map.Entry<String, DomainObj> entry : map.entrySet()) {
        if (valueToRemove.equals(entry.getValue())) {
            removalKey = entry.getKey();
            break;
        }
    }

    if (removalKey != null) {
        map.remove(removalKey);
    }
4b9b3361

Ответ 2

Правильный и быстрый однострочник будет:

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

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

Ответ 3

Здесь однострочное решение:

map.values().remove(valueToRemove);

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

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

Ответ 4

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

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.
    }
}

Ответ 6

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

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

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

Ответ 7

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

 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

Ответ 8

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

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

Ответ 9

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

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

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

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

==================== Добавление: Это, по сути, то, что @msaeed предлагает просто без сторонней библиотеки.

Ответ 10

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

DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
        if (valueToRemove.equals(it.next())) {
                it.remove();
                break;
        }
}

Ответ 11

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

Ответ 12

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

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

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

 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 );
           }
     }
  }

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

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

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

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