Hashmap.keySet (), foreach, и удаляют

Я знаю, что это обычно - большое нет - нет для удаления из списка с помощью "foreach" Java и что нужно использовать iterator.remove (). Но действительно ли безопасно удалить (), если я - цикличное выполнение по набору ключей HashMap ()? Как это:

for(String key : map.keySet()) {
  Node n = map.get(key).optimize();
  if(n == null) {
   map.remove(key);
  } else {
   map.put(key, n);
  }
}
14
задан kgiannakakis 8 January 2010 в 07:33
поделиться

2 ответа

Вот мое решение в Clojure:

(defstruct BST :val :left :right)

(defn in-order [bst]
  (when-let [{:keys [val, left, right]} bst]
    (lazy-seq
      (concat (in-order left) (list val) (in-order right)))))

(defn is-strictly-sorted? [col]
  (every?
    (fn [[a b]] (< a  b))
    (partition 2 1 col)))

(defn is-valid-BST [bst]
  (is-strictly-sorted? (in-order bst)))
-121--2047455-

Я бы пошел с «C++ Coding Standards: 101 Rules, Guidelines, and Best Practices»: если вы можете сделать это как функция, не являющаяся членом, сделать это как функция, не являющаяся членом (в том же пространстве имен).

Одна из причин: он лучше работает с неявным преобразованием типа. Пример: имеется сложный класс с перегруженным оператором *. Если нужно записать 2.0 * aComplexNumber, оператор * должен быть функцией, не являющейся членом.

Еще одна причина: меньшее сцепление. Функции, не являющиеся членами, менее тесно связаны, чем функции членов. Это почти всегда хорошо.

-121--3033955-

EDIT:

Я не заметил, что вы не добавили на карту - вы просто изменили значение в записи. В этом случае решение pstanton (pre-edit 1 ) имеет значение почти , но следует вызвать setValue для записи, возвращенной итератором, а не вызывать map.put . (Возможно , что map.put будет работать, но я не верю, что это гарантировано - тогда как в документах указано, что entry.setValue будет работать .)

for (Iterator<Map.Entry<String, Node>> it = map.entrySet().iterator(); 
     it.hasNext();)
{
    Map.Entry<String, Node> entry = it.next();
    Node n = entry.getValue().optimize();
    if(n == null) 
    {
        it.remove();
    }
    else
    {
        entry.setValue(n);
    }
}

(Жаль, что запись не имеет метода remove , в противном случае можно использовать расширенный синтаксис цикла, что делает его несколько менее скрытым.)

Старый ответ

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

Нет - нельзя добавлять на карту или удалять ее напрямую. Набор, возвращенный HashSet.keySet () , является представлением ключей, а не снимком.

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

Один простой вариант - создать новый набор из оригинала:

for (String key : new HashSet<String>(map.keySet())) {
    ...
}

На данный момент вы в порядке, потому что вы не вносите никаких изменений в набор.

EDIT: Да, вы можете удалить элементы через итератор набора клавиш. Из документов для HashMap.keySet () :

наборы поддерживает удаление элемента, который удаляет соответствующее отображение из карты, через Iterator.remove, Set.remove, remureAll, retainAll и clear операции. Он не поддерживает операции add или addAll.

Это даже указано в самом интерфейсе Map .


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

18
ответ дан 1 December 2019 в 09:01
поделиться

Вы должны использовать набор ввода:

for(Iterator<Map.Entry<String, Node>> it = map.entrySet().iterator(); it.hasNext();)
{
      Map.Entry<String, Node> entry = it.next();
      Node n = entry.getValue().optimize();
      if(n == null) 
          it.remove();
      else
          entry.setValue(n);
}

Редактировать фиксированный код

12
ответ дан 1 December 2019 в 09:01
поделиться
Другие вопросы по тегам:

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