Reputation: 132994
OK, here is yet another question of the "How to do it better in STL?" series.
We have two ranges, designated by first1, last1, and first2. We want to find the number of different i's from [0, last1-first1] such that *(first1 + i) == *(first2 + i)
For example:
{a, b, c, d, d, b, c, a}
{a, a, b, c, d, c, c, a}
^ ^ ^ ^
For these two ranges the answer is 4.
Is there a good STL way to do it? I mean preferrably without any manual for's, while's etc. Thanks!
Upvotes: 3
Views: 290
Reputation: 272497
std::inner_product(first1, last1, first2, 0, std::plus<T>(), std::equal_to<T>());
UPDATE
Konrad has pointed out in the comments below that this relies on slightly nefarious implicit conversion from bool
to int
. Whilst this is completely legal, it can be avoided thus:
template <typename T>
int match(const T &a, const T &b) { return (a == b) ? 1 : 0; }
std::inner_product(first1, last1, first2, 0, std::plus<T>(), match<T>);
Upvotes: 12
Reputation: 45224
I've come up with the following solution, insipired by functional languages' zip()
functions. It compiles and runs fine, but IMHO, this is probably the most unsafe use of begin()
& end()
iterator pairs I've ever come across, so I don't recommend using it in production code as is.
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <iostream>
#include <vector>
namespace {
// Iterator for pairs of items at same position in two sequences.
template<typename Lhs, typename Rhs>
class zipper
{
// Keep track of position in input sequences.
Lhs myLhs;
Rhs myRhs;
public:
// Minimal assumptions on iterator types `Lhs` and `Rhs`.
typedef std::input_iterator_tag iterator_category;
typedef std::pair<
typename std::iterator_traits<Lhs>::value_type,
typename std::iterator_traits<Rhs>::value_type
> value_type;
typedef value_type& reference;
typedef value_type* pointer;
typedef std::ptrdiff_t difference_type;
zipper ( Lhs lhs, Rhs rhs )
: myLhs(lhs), myRhs(rhs)
{}
value_type operator* () const {
return (value_type(*myLhs, *myRhs));
}
bool operator== ( const zipper<Lhs,Rhs>& other ) const {
return ((myLhs == other.myLhs) && (myRhs == other.myRhs));
}
bool operator!= ( const zipper<Lhs,Rhs>& other ) const {
return ((myLhs != other.myLhs) || (myRhs != other.myRhs));
}
zipper<Lhs,Rhs>& operator++ () {
++myLhs, ++myRhs; return (*this);
}
zipper<Lhs,Rhs> operator++ ( int ) {
const zipper<Lhs,Rhs> old(*this);
++(*this); return (old);
}
};
// Shorthand "a la" std::make_pair().
template<typename Lhs, typename Rhs>
zipper<Lhs,Rhs> make_zipper ( Lhs lhs, Rhs rhs )
{
return (zipper<Lhs,Rhs>(lhs, rhs));
}
// Check for equal items in a pair.
template<typename T> struct equal_pair
{
bool operator() ( const std::pair<T,T>& x ) const
{
return (x.first == x.second);
}
};
}
int main ( int, char ** )
{
// Test data.
const std::string lhs("abcddbca");
const std::string rhs("aabcdcca");
// Count how many pairs are equal.
const std::size_t equal_pairs = std::count_if(
make_zipper(lhs.begin(),rhs.begin()),
make_zipper(lhs.end() ,rhs.end() ), equal_pair<char>());
// Outputs "There are 4 equal pairs.".
std::cout
<< "There are " << equal_pairs << " equal pairs." << std::endl;
}
Upvotes: 2
Reputation: 18652
You can abuse the std::mismatch algorithm (and lambda function):
const int lista[] = { 1, 2, 3, 4, 4, 2, 3, 1 };
const int listb[] = { 1, 1, 2, 3, 4, 3, 3, 1 };
int count = 0;
std::mismatch(lista, lista+8, listb, [&count](int a, int b)->bool
{
if (a == b) ++count;
return true;
});
std::cout << count << '\n';
Upvotes: 1
Reputation: 54148
You could use std::transform on the two ranges with a stateful binary functor that increments a counter on match.
Holding my nose, since this keeps state as a static member. You can avoid the 'write back to source' that @Johannes raised using equal
rather than transform
but statefulness via static
is still messy here (in my code anyhow).
#include <vector>
#include <algorithm>
class match {
public:
char operator()(const char& lhs, const char& rhs)
{
if (lhs == rhs)
{
++count;
}
return rhs;
}
static size_t count;
};
size_t match::count(0);
class matchEqual {
public:
bool operator()(const char& lhs, const char& rhs)
{
if (lhs == rhs)
{
++count;
}
return false;
}
static size_t count;
};
size_t matchEqual::count(0);
int main()
{
vector<char> vec1;
vec1.push_back('a');
vec1.push_back('b');
vec1.push_back('c');
vec1.push_back('d');
vec1.push_back('d');
vec1.push_back('b');
vec1.push_back('c');
vec1.push_back('a');
vector<char> vec2;
vec2.push_back('a');
vec2.push_back('a');
vec2.push_back('b');
vec2.push_back('c');
vec2.push_back('d');
vec2.push_back('c');
vec2.push_back('c');
vec2.push_back('a');
transform(vec1.begin(), vec1.end(), vec2.begin(), vec2.begin(), match());
size_t matches = match::count;
equal(vec1.begin(), vec1.end(), vec2.begin(), matchEqual());
matches = matchEqual::count;
return 0;
};
Upvotes: 0