JuniorКодЧастоЕщё не отвечали
Удалите из unordered_map элементы, которые делятся на 2, и выведите ключи этих элементов
Дан std::unordered_map<int, int>. Удалите каждую запись, значение которой чётное, и выведите ключ каждой удалённой записи.
Требования:
- Нельзя удалять во время итерации обычным range-for (это инвалидирует итератор).
- Порядок вывода для
unordered_mapне гарантирован.
#include <unordered_map>
void removeEvenValues(std::unordered_map<int, int>& m) {
// ваш код здесь
}
Допишите реализацию.
Нельзя удалять элементы из контейнера, итерируя его с range-for — это инвалидирует итератор. Безопасные подходы: собрать ключи для удаления, затем удалить отдельным проходом; или использовать std::erase_if (C++20), который делает это аккуратно.
- ✗Удалять элементы внутри range-for — неопределённое поведение из-за инвалидации итератора
- ✗Использовать
map.erase(it)без сохранения возвращённого итератора на следующий элемент в ручном цикле - ✗Не знать о
std::erase_if(C++20) — самое чистое решение
- →Что такое инвалидация итератора и какие контейнеры наиболее/наименее подвержены ей?
- →Как
eraseвозвращает следующий допустимый итератор в большинстве контейнеров?
Оглавление
Задача
Дан std::unordered_map<int, int>. Удалите все записи, у которых значение чётное, и выведите ключи удалённых элементов.
Решение
#include <unordered_map>
#include <vector>
#include <iostream>
#include <algorithm>
// Подход 1: собрать ключи, потом удалить (pre-C++20)
void removeEvenValues(std::unordered_map<int, int>& m) {
std::vector<int> toErase;
for (const auto& [key, val] : m) {
if (val % 2 == 0) {
toErase.push_back(key);
std::cout << key << ' ';
}
}
std::cout << '\n';
for (int k : toErase) m.erase(k);
}
// Подход 2: ручная итерация с it = erase(it) (pre-C++20)
void removeEvenValuesManual(std::unordered_map<int, int>& m) {
for (auto it = m.begin(); it != m.end(); ) {
if (it->second % 2 == 0) {
std::cout << it->first << ' ';
it = m.erase(it); // erase возвращает следующий итератор
} else {
++it;
}
}
std::cout << '\n';
}
// Подход 3: std::erase_if (C++20) — наилучший
void removeEvenValuesModern(std::unordered_map<int, int>& m) {
std::erase_if(m, [](const auto& kv) {
if (kv.second % 2 == 0) {
std::cout << kv.first << ' ';
return true;
}
return false;
});
std::cout << '\n';
}
int main() {
std::unordered_map<int, int> m = {{1,1},{2,4},{3,9},{4,16},{5,25}};
removeEvenValuesManual(m); // выводит: 2 4 (или 4 2, порядок не гарантирован)
// m теперь содержит только нечётные значения: {1:1, 3:9, 5:25}
}
Ключевые моменты
- Никогда не удаляйте из контейнера внутри range-for — это UB.
erase(it)возвращает следующий допустимый итератор.std::erase_if(C++20) — самый чистый и идиоматичный вариант.- Порядок вывода не гарантирован для
unordered_map.
Оглавление