Как проверить, существует ли ключ на карте
В этом кратком руководстве мы рассмотрим способы проверить, существует ли ключ вMap.
В частности, мы сосредоточимся наcontainsKey andget.
2. containsKeyс
Возвращает true , если эта карта содержит отображение для указанного ключа
Мы видим, что этот метод является довольно хорошим кандидатом на то, что мы хотим.
Давайте создадим очень простую карту и проверим ее содержимое с помощьюcontainsKey:
Проще говоря,containsKey показывает, содержит ли карта этот ключ.
3. getс
Теперь сканированиеget тоже иногда работает, но оно имеет некоторый багаж, в зависимости от того, поддерживает ли реализацияMap нулевые значения.
Опять же, взглянув на JavaDocMap, на этот раз дляMap#put, мы видим, что он выдаст толькоNullPointerException:
если указанный ключ или значение равно нулюand this map does not permit null keys or values
Поскольку некоторые реализации сканированияMap имеют нулевые значения (например,HashMap),get может возвращатьnull даже при наличии ключа.
Итак, если наша цель — увидеть, имеет ли ключ значение или нет, тоget будет работать:
Но если мы просто пытаемся проверить, существует ли ключ, мы должны придерживатьсяcontainsKey.
4. Заключение
В этой статье мы рассмотрелиcontainsKey. Мы также более подробно рассмотрели, почему использоватьget для проверки существования ключа рискованно.
Небольшие, но важные функции
Начиная с C++20 в несколько стандартных контейнеров, включая std::map , std::set и std::string , были добавлены некоторые очень полезные функции для поиска. Необходимость в них существовала уже в течении достаточно долгого времени, и мне приятно видеть, что комитет наконец признал их важность. Надеюсь, это только начало серии замечательных дополнений.
Map и set
Типовая операция при работе с map — проверить, существует ли конкретный ключ. Как это сделать в C++17? Все просто:
Хотя это может быть достаточно просто, это отнюдь совсем не удобно для пользователя. По этой причине многие пишут свою собственную функцию contains() , которая принимает map и ключ и возвращает логическое значение, указывающее, содержит ли map ключ. В C++20 это больше не нужно, т.к. std::map имеет родной метод contains() .
То же верно и для std::set
Даже больше, в C++20 функция contains() была добавлена к целому ряду типов:
Строки
Похожая проблема актуальна и для строк. Иногда нам нужно узнать, содержит ли строка другую строку. Вот как это делается в C++17:
Частный случай, связанный со строками, — это поиск подстроки в начале и в конце строки. Поиск в начале относительно прост:
Но для поиска в конце требуется вспомогательная функция. Возможная реализация такова:
Что можно использовать следующим образом:
(Примечание: Вы можете найти альтернативные реализации этой функции здесь)
C++20 значительно упростил ситуацию, где std::basic_string и std::basic_string_view получили два новых метода: starts_with() и ends_with()
Однако в C++20 есть достаточно большое упущение: функция для проверки того, содержит ли строка подстроку. Во время последнего заседания комитета ISO C++, такой метод был добавлен в C++23 (P1679). Это позволит нам написать следующее:
Именно так мы всегда и хотели писать код.
Вы должны помнить, что эти новые строковые функции чувствительны к регистру. Они не принимают предикат, позволяющий настроить способ выполнения поиска. Следовательно, если вам нужно выполнить поиск без учета регистра, вам все равно нужно будет реализовать это самостоятельно. Возможные реализации contains() , startwith() и endwith() , которые выполняют поиск без учета регистра, показаны ниже:
8 хитрых приемов написания кода на Go

Я использую Go уже несколько лет, и иногда удается обнаружить маленькие хитрости в написании кода, которые облегчают мне жизнь. Сегодня я поделюсь ими с вами!
1. Проверка наличия ключа в map
Этот прием наверняка многие уже знают, но я так часто его применяю, что просто не могу о нем не упомянуть. Чтобы проверить, есть ли ключ в map , просто вызываете:
2. Проверка при приведении типов переменной
Иногда нужно провести преобразование переменных из одного типа в другой. Проблема в том, что в случае неверного типа код запаникует. Например, следующий код пытается привести переменную data к строковому типу string :
Здесь преобразование data в тип string не произойдет, поэтому код запаникует. Но есть способ лучше! Аналогично проверке наличия ключа в map : при приведении типов получаем логическое значение и проверяем, произошло приведение или нет:
В этом примере ok — логическое значение, которое сообщает, было ли приведение типов успешным или нет. Таким образом работа с несоответствием типов ведется более изящно, чем при механизме паники.
3. Указание размера массива при использовании append
Для добавления элементов в массив лучше всего задействовать append . Например:
Однако в случае больших массивов процесс добавления замедлится, потому что append потребуется постоянно увеличивать размер myArray для новых значений. Лучше сначала указать длину массива, а затем присвоить каждое значение напрямую:
Есть и третий вариант, который мне нравится еще больше: он сочетает два предыдущих! Считаю его чуть более удобным для восприятия, к тому же он не приводит к потери скорости, ведь размер назначается вначале:
Здесь размер массива устанавливается равным 0, а максимальный размер задается равным длине входного массива. Поэтому append не потребуется менять размер на ходу. При сравнении времени трех вариантов на массиве из 100 миллионов целых чисел разница в скорости очевидна:
4. Использование append и многоточия для объединения массивов
Иногда бывает нужно объединить два массива. И тогда очень кстати, что append — это функция с переменным числом аргументов. Посмотрите, как выглядит обычный вызов append :
И append позволяет добавлять несколько элементов одновременно:
Но самое крутое — это расширение массива с помощью … при передаче его в функцию. Итак, объединяем массив inputArray с массивом myArray :
При этом происходит увеличение количества значений массива inputArray и передача их в append .
5. Отображение имен и значений параметров при выводе
Осваивать этот прием пришлось очень долго, зато теперь я все время им пользуюсь. Раньше для отображения имен и значений параметров в структуре я выполнял маршалинг в JSON и логировал это. Но есть гораздо более простой способ: при выполнении Printf добавлять + в формат. Пример:
Для получения такого же вывода на Go надо поменять в его синтаксическом представлении + на # :
Сравнение разных выводов:
6. Задействование iota с пользовательскими типами при перечислении
При перечислении в Go лучше использовать ключевое слово iota . При каждом вызове оно присваивает увеличивающиеся целочисленные значения. Это отлично подходит для создания перечислений и задействуется вместе с пользовательским целочисленным типом так, чтобы компилятор гарантировал применение пользователями кода только указанных перечислений. Пример:
Здесь создается пользовательский тип PossibleStates («возможные состояния»), после чего каждое перечисление будет иметь тип PossibleState , значение которого присваивается ключевым словом iota . Затем, когда кто-то вызывает updateState , компилятор гарантирует отправку только этих possible states , а не прежних int .
7. Использование в качестве параметров (при создании имитированного интерфейса) функций, соответствующих интерфейсным функциям
Этот прием стал для меня откровением. Допустим, имеется интерфейс, который надо сымитировать:
Это интерфейс для нескольких различных типов этой persistence («сохраняемости»). Нужно протестировать код, поэтому создадим имитированную структуру DataPersistence для использования в тестах. Но вместо написания сложной имитированной структуры просто создадим структуру с параметрами, которые являются функциями, соответствующими интерфейсным функциям. Немного запутанное предложение. Распутать поможет хороший пример! Вот как будет выглядеть имитация:
Это означает, что при тестировании функции настраиваются, как нам надо, прямо в этом же тесте:
Удобство восприятия действительно улучшается: теперь видно очень хорошо, на что способна имитация в каждом тесте. Кроме того, теперь у нас есть доступ к тестовым данным в имитированной функции без необходимости поддерживать внешние файлы данных.
8. Создание собственного интерфейса в случае его отсутствия
Допустим, вы используете другую библиотеку Go, и там есть структура, но интерфейса из нее не сделано — создайте его сами. Вот, например, эта структура:
Прямо в коде создаем интерфейс, который ее реализует:
Затем пишем код, чтобы принять этот интерфейс. Передаем структуру другой библиотеки при ее использовании. Затем, когда понадобится ее протестировать, выполняем трюк с имитированным интерфейсом.
Бонус: инстанцирование вложенных анонимных структур
А этот прием мне приходилось задействовать несколько раз при использовании сгенерированного кода. Иногда при генерировании кода получается вложенная анонимная структура. Пример:
Допустим, теперь надо создать экземпляр этой структуры для использования. Как это сделать? С Value1 и Value2 все просто, но как инстанцировать указатель на анонимную структуру (Value3)? Мое первое решение: написать его в JSON, а затем маршалировать в структуру. Но это ужасно и как-то по-дилетантски. Оказывается, нужно использовать другую анонимную структуру при ее инстанцировании:
Это очевидно, но имейте в виду, что она должна точно соответствовать, вплоть до тегов JSON. И хотя все это будет работать, но из-за несоответствия типов не удастся скомпилировать следующее:
Как узнать, существует ли данный ключ в C ++ std :: map
Я пытаюсь проверить, находится ли данный ключ на карте, и несколько не может этого сделать:
так как я могу напечатать то, что находится в p?
12 ответов
Чтобы проверить, существует ли конкретный ключ на карте, используйте функцию-член count одним из следующих способов:
документация для map::find говорит: «Другая функция-член, map::count , может использоваться, чтобы просто проверить, существует ли конкретный ключ.»
documentation для map::count говорит:» Поскольку все элементы в контейнере карты уникальны, функция может возвращать только 1 (если элемент) или ноль (в противном случае).
Чтобы получить значение с карты с помощью ключа, который, как вы знаете, существует, используйте map:: at:
В отличие от map:: operator [], map::at не создаст новый ключ на карте, если указанный ключ не существует.
Вы можете использовать .find() :
Если вы хотите использовать другой API, то найдите m.count(c)>0
Я думаю, вы хотите map::find . Если m.find(«f») равно m.end() , ключ не был найден. В противном случае find возвращает итератор, указывающий на найденный элемент.
Ошибка связана с тем, что p.first является итератором, который не работает для вставки потока. Измените свою последнюю строку на cout << (p.first)->first; . p — пара итераторов, p.first — итератор, p.first->first — ключевая строка.
В карте может быть только один элемент для заданного ключа, поэтому equal_range не очень полезен. Он определен для карты, потому что он определен для всех ассоциативных контейнеров, но это намного интереснее для мультимапа.
Конечно, если бы вы хотели получить fancier, вы всегда могли бы отформатировать функцию, которая также приняла найденную функцию и не найденную функцию, что-то вроде этого:
И используйте его следующим образом:
Недостатком этого является хорошее имя, «find_and_execute» неудобно, и я не могу придумать ничего лучше с моей головы.
существует ключ проверки или нет, и возвращается число событий (0/1 в карте):