如何在 c++ 中计算 2 个不同向量的相等元素

How to count the equal elements of 2 different vectors in c++?

本文关键字:向量 元素 c++ 计算      更新时间:2023-10-16

我正在尝试找到一种方法来计算 c++ 中相同大小的 2 个不同向量中有多少元素相等。向量包含结构,我想通过示例中显示的结构的双变量来比较相等性。

并说清楚。我不想检查 2 个向量是否相等,而只想计算它们的元素数量。

以下方法不起作用。它给出地址而不是值。此外,如果我尝试像pointsA[j].dist一样访问 dist 变量,则会出现错误。

vector<struct PointWithDistance*> pointsA, pointsB;
//the struct
struct PointWithDistance {
    Point *p;
    double dist;
};
for (int j = 0; j < k; j++){
    if (pointsA[j] == pointsB[j])
        equalCount++;
}
vector<struct PointWithDistance*> pointsA, pointsB;

你的意思是使用指针吗?如果是这样,您必须执行*(points[A])(和 b(,因为您当前的比较比较的是指针,而不是它们的内容。

另外,结构Point是否有operator ==以便可以对类型进行比较?

你想强制相同的位置吗?比如说,一个向量{1,2,3}和一个由你的算法{2,3,4}的向量将有 0 项相等,你想要吗?如果没有,则循环第一个向量,并在每个元素上使用std::find(如果向量已排序,则std::upper_bound(到第二个向量。

一些快速代码:

template <typename T=int> struct Point
{
 T x,y;
 bool operator==(const T& t) { return (x == t.x && y == t.y); }
};
std::vector<Point<>> p1 = {1,2,3}; 
std::vector<Point<>> p2 = {2,3,4}; 
for(auto& p : p1)
{
   if (std::find(p2.begin(),p2.end(),p) != p2.end())   
   {
    // similar++;
   }
}
// or
assert(p1.size() == p2.size());
for(size_t i1 = 0 ; i1 < p1.size() ; i1++)
{
    if (p1[i1] == p2[i1]) 
    {
    // equal++;
    }
}

计算 2 个容器中重复项数的通用解决方案如下所示。如果在容器中找到元素,则使用 std::transform_reduce 添加(std::plus<>{}(布尔结果。请注意,只要它们包含的类型保持不变,它就可以访问两种不同类型的容器(例如 std::vector<int>std::set<int>(。容器的长度不必相等。有两种 SFINAE 实现可以区分 T 是指针的情况和不是指针的情况:

#include <algorithm>   //std::find, std::find_if
#include <cstddef>     //std::size_t
#include <functional>  //std::plus, 
#include <iterator>    //std::cbegin, std::cend
#include <numeric>     //std::transform_reduce
#include <type_traits> //std::enable_if_t, std::is_pointer_v
namespace {
    //core implementation for duplicate_count
    template<class C, class F>
    std::size_t duplicate_count_impl(const C& container, F pred) {
        return std::transform_reduce(std::cbegin(container), std::cend(container), std::size_t{}, std::plus<>{}, pred);
    }
}
//returns the number of duplicates in two (different) containers.
//overload for containers where T is a pointer type.
template<typename T, template <typename...> class C1, template <typename...> class C2, std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
std::size_t duplicate_count(const C1<T>& a, const C2<T> &b) {
    return duplicate_count_impl(b, [&](T ptr_b) -> bool {
        return std::find_if(std::cbegin(a), std::cend(a), [&](T ptr_a) -> bool {
            return *ptr_a == *ptr_b;
        }) != std::cend(a);
    });
}
//returns the number of duplicates in two (different) containers.
//overload for containers where T is not a pointer type.
template<typename T, template <typename...> class C1, template <typename...> class C2, std::enable_if_t<!std::is_pointer_v<T>>* = nullptr>
std::size_t duplicate_count(const C1<T>& a, const C2<T> &b) {
    return duplicate_count_impl(b, [&](T n) -> bool {
        return std::find(std::cbegin(a), std::cend(a), n) != std::cend(a);
    });
}

#include <iostream>
#include <vector>
#include <list>
//[duplicate_count implementations]
struct Point {
    int a, b;
    bool operator==(const Point& other) const {
        return this->a == a && this->b == other.b;
    }
};
int main() {
    {
        std::list<int> v = { 1, 2, 7, 7 };
        std::list<int> u = { 0, 1, 2, 7 };
        std::cout << "list<int>t number of duplicates: " << duplicate_count(v, u) << 'n';
    }
    {
        auto[a, b, c, d] = std::make_tuple(0, 1, 2, 3);
        std::vector<int*> v = { &b, &c, &d, &d };
        std::vector<int*> u = { &a, &b, &c, &d };
        std::cout << "vector<int*>t number of duplicates: " << duplicate_count(v, u) << 'n';
    }
    {
        auto[a, b, c, d] = std::make_tuple(
            Point{ 0, 0 }, 
            Point{ 1, 1 },
            Point{ 2, 2 }, 
            Point{ 4, 4 });
        std::vector<Point*> v = { &b, &c, &d, &d };
        std::vector<Point*> u = { &a, &b, &c, &d };
        std::cout << "vector<Point*>t number of duplicates: " << duplicate_count(v, u) << 'n';
    }
}
list<int>        number of duplicates: 3
vector<int*>     number of duplicates: 3
vector<Point*>   number of duplicates: 3

您显示的解决方案良好、快速且高效。

它有一些可以轻松解决的小问题。在您的定义vector<struct PointWithDistance*> pointsA, pointsB;中,变量点 A 和点 B 是向量,包含指向结构的指针。

使用 pointsA[n],您将获得指向该结构的指针。但是你想要结构本身。因此,您只需要取消引用获取的指针即可。由于你想访问结构的成员(通常使用变量.member完成(,你可以使用(*(pointsA[j]((.dist或pointsA[j]->dist。

如果向量的大小保证相同,则只需将代码更新为

vector<struct PointWithDistance*> pointsA, pointsB;
//the struct
struct PointWithDistance {
    Point *p;
    double dist;
};
for (int j = 0; j < k; j++){
    if (pointsA[j]->dist == pointsB[j]->dist)
        equalCount++;
}

那是你唯一缺少的东西。

您可以使用 std::inner_product 算法:

#include <iostream>
#include <numeric>
#include <vector>
int main () {
   const std::vector a{7, 7, 7, 7};
   const std::vector b{7, 6, 7, 7};
   const auto equalCount = std::inner_product(
      a.begin(), a.end(), b.begin(), 0,
      std::plus<>(), std::equal_to<>()
   );
   std::cout << equalCount << " of the elements are equal.n";
}

输出

3 of the elements are equal.

它是标准内积的概括,使用+(加号(和==(equal_to(函数,而不是+*.因此,它计算 0 + (a[0] == b[0]) + (a[1] == b[1]) + ... .

这利用了false/true可以解释为0/1的事实。