C++/counting certain characters in a vector
Expert: Ralph McArdell - 1/17/2012
Questionhalo mr.mcardell.
my question is simple,how do i count certain characters in a vector,for example,if the vector contained the following: 00112301230223332103 how would i count the number of threes,for example in the vector?or the number of twos?
thanks in advance.
AnswerI would like to start by stating the assumptions I have made from your question for the purposes of the answer:
1/ by 'vector' I am assuming you mean a single dimension array, specifically a C++ library std::vector type.
It seems that a std::vector<int> would suffice to hold the values you show.
Hence it is assumed that the standard C++ library header vector has been included somewhere suitable before example code snippets.
2/ By "00112301230223332103" you mean a list of single digit numbers, not one large integer or some mix of values of various digit length ( e.g. not 00, 11, 230, 1230, 223, 33210,3)
There are obviously many ways we could achieve this - the basic idea is:
for each element of the vector
if element equals value to match increment count of matches
end for each.
We could use an explicit loop to iterate over the vector and check each element for a match. However the C++ standard library, in addition to various container type templates such as std::vector also come with various algorithms to work on them - or in fact on sequences of data.
Sequences are defined by a start position and an end position. End positions are in fact specified to be one-past-the-end of the elements in the sequence to be processed. The types used to represent positions are called iterators and can be thought of as a generalisation of pointers.
The most common requirement is to apply an algorithm to all elements in a container, and for this each container provides begin and end operations to provide iterators to the first and one past the last element of the container.
We can use begin and end with an explicit for-loop for example:
typedef std::vector<int> ValueCollectionType;
ValueCollectionType theValues;
// Code to add values to the theValues vector (not shown)
ValueCollectionType::iterator position( theValues.begin() );
ValueCollectionType::iterator finish( theValues.end() );
int count(0);
int const ValueToCountInstancesOf(3);
for ( ; position!=finish; ++position )
{
if (*position==ValueToCountInstancesOf)
{
++count;
}
}
You will notice that like pointers we can dereference iterators to obtain a reference to the element at that position, and also increment them (to the next element in the sequence) and compare two iterators for equality or inequality. Some iterator types allow additional operations.
As an aside, we can of course use a similar for-loop using array like subscripts instead of iterators:
typedef std::vector<int> ValueCollectionType;
ValueCollectionType theValues
// Code to add values to the theValues vector (not shown)
int count(0);
int const ValueToCountInstancesOf(3);
for ( unsigned int i=0; i!=theValues.size(); ++i )
{
if (theValues[i]==ValueToCountInstancesOf)
{
++count;
}
}
From the algorithms supplied by the C++ library the most obvious algorithm to use would be the std::for_each algorithm (include the standard C++ library header algorithm):
std::for_each( theValues.begin(), theValues.end(), function_to_do_stuff );
The function_to_do_stuff argument would be the name (and therefore pointer or reference to a function) which gets passed the value of each element in turn. However, we need to remember the count between calls, and that would imply using a static, probably global, value for count - not a good design.
There is another option. We can instead use a functor object. A functor object is an instance of a class that provides an operator() (the function call operator). Instances of such classes can be 'called' like a function:
class SimpleFunctor
{
public:
void operator()(int element)
{
std::cout << element << ", ";
}
};
We could use objects of the SimpleFunctor type like so:
SimpleFunctor fntor;
std::cout << "Calling a SimpleFunctor instance with value 6:\n";
fntor(6); // outputs "6, "
std::cout << std::endl;
(remember to include the iostream C++ library header for std::cout).
Now we have class instances that can be used like functions BUT they can contain additional state so we might try writing a functor that counts occurrences of a specific value - specified during instance construction:
class CountValueOccurence
{
int searchValue;
int count;
public:
CountValueOccurence( int value )
: searchValue(value)
, count(0)
{}
void operator()(int element)
{
if ( element==searchValue )
{
++count;
}
}
int getCount() { return count; }
};
We could then try something like so:
CountValueOccurence countThrees(3);
std::for_each( theValues.begin(), theValues.end(), countThrees );
std::cout << "The vector contained " << countThrees.getCount() << " threes.\n";
In fact this does not work as a copy of the countThrees functor object is passed to for_each and so it is the copy that receives the count and not countThrees - doh!
Fortunately for_each - unlike other functor taking algorithms - returns the functor it does use so instead we can use:
CountValueOccurence countThrees( std::for_each(theValues.begin(), theValues.end(), CountValueOccurence(3)) );
std::cout << "The vector contained " << countThrees.getCount() << " threes.\n";
However doing the sort of counting operation you want is so common that the C++ standard library includes algorithms to do it! The simplest counting algorithm is std::count (again include header algorithm), and does what you mention in your question:
int count( std::count(theValues.begin(), theValues.end(), 3) );
std::cout << "The vector contained " << count << " threes.\n";
Which will initialise the value of count to the number of elements in theValues whose value equals 3.
Note that int is possibly not the exact returned type from std::count - it is in fact governed by a traits type for InputIterator types for the C++ library implementation in question (std::iterator_traits<InputIterator>::difference_type if you really want to know!).
For more information on the C++ library I suggest you get yourself a good reference such as "The C++ Standard Library A Tutorial and Reference" by Nicolai M. Josuttis. The concepts and details of the things discussed here are all covered along with a whole lot more.