Форум » C/C++ для начинающих (C/C++ for beginners) » Как подсчитать количество заданных элементов в контейнере? » Ответить

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

Сыроежка: Иногда возникает задача подсчета заданных элементов в контейнере. Например, пусть имеется массив целых чисел [pre2] int a[] = { 1, 2, 3, 1, 2, 2 }; [/pre2] и требуется подсчитать, сколько раз в этом массиве присутствуют значения 1 и 2. Как это можно сделать для произвольных контейнеров и заданных значений, написав соответствующую функцию? На ум помимо обычных циклов сразу же приходит стандартный алгоритм std::count или std::count_if. Один из подходов может выглядеть следующим образом [pre2] #include <iostream> #include <algorithm> #include <iterator> #include <initializer_list> template <typename R, typename T> auto matches( const R &range, std::initializer_list<T> lst ) { return std::count_if( std::begin( range ), std::end( range ), [&]( auto x ) { return std::binary_search( std::begin( lst ), std::end( lst ), x ); } ); } int main() { int a[] = { 1, 2, 3, 1, 2, 2 }; std::cout << matches( a, { 1, 2 } ) << std::endl; } [/pre2] Вывод программы на консоль [pre2] 5 [/pre2] В этой реализации функции помимо стандартного алгоритма std::count_if используется алгоритм std::binary_search. Чтобы его можно было использовать в данном контексте, заданные значения должны быть отсортированы, чтобы образовать отсортированный список инициализации. Другой подход - это использовать так называемые "сворачиваемые выражения" (fold expressions), введенные в стандарте C++ 17. Вот как будет выглядеть соответствующая реализация функции. [pre2] #include <iostream> #include <algorithm> #include <iterator> template <typename R, typename ...Ts> auto matches( const R &range, Ts... ts ) { return ( std::count( std::begin( range ), std::end( range ), ts ) + ... + 0 ); } int main() { int a[] = { 1, 2, 3, 1, 2, 2 }; std::cout << matches( a, 1, 2 ) << std::endl; } [/pre2] Здесь уже не важно отсортированы ли заданные значения или нет, так как алгоритм std::count вызывается отдельно для каждого заданного значения. Если у вас есть свои идеи, как выполнить эту задачу, то можете разместить сообщения к теме со своими предложениями.

Ответов - 1

Сыроежка: Похожая задача возникает, когда надо добавить в вектор несколько элементов. До введения стандарта C++ 17 это можно было сделать с использованием метода insert и списка инициализации. Ниже приведена демонстрационная программа [pre2] #include <iostream> #include <vector> int main() { std::vector<int> v( { 1, 2, 3 } ); v.insert( v.end(), { 4, 5, 6 } ); for ( const auto &item : v ) std::cout << item << ' '; std::cout << std::endl; } [/pre2] Вывод программы на консоль [pre2] 1 2 3 4 5 6[/pre2] С появлением стандарта C++ 17 можно написать обобщенную функцию следующего вида, как показано в последующей демонстрационной программе. [pre2] #include <iostream> #include <vector> template <typename T, typename ...Ts> void insert_all( std::vector<T> &v, Ts... ts ) { v.reserve( v.size() + sizeof...( ts ) ); ( v.push_back( ts ), ... ); } int main() { std::vector<int> v( { 1, 2, 3 } ); insert_all( v, 4, 5, 6 ); for ( const auto &item : v ) std::cout << item << ' '; std::cout << std::endl; } [/pre2]



полная версия страницы