You are here:

C++/counting certain characters in a vector

Advertisement


Question
halo 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.

Answer
I 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.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.