number of matches in two sequences with STL

梦想与她 提交于 2019-12-22 09:40:02

问题


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!


回答1:


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>);



回答2:


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;
}



回答3:


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';



回答4:


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;
};


来源:https://stackoverflow.com/questions/4125536/number-of-matches-in-two-sequences-with-stl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!