简体   繁体   English

查找 class 实例是否包含在 std::vector (C++) 中的优雅方法

[英]Elegant way to find if a class instance is contained in a std::vector (C++)

I want to construct a vector that will hold int M elements of my class Point which represent a single point (x,y) where both x,y are int .我想构造一个向量来保存我的 class Pointint M个元素,这些元素代表一个点 (x,y),其中 x,y 都是int

The points that will be stored in this vector are randomly generated.将存储在此向量中的点是随机生成的。 However, I do not want to store the same point more than once.但是,我不想多次存储同一点。

My implementation is the following:我的实现如下:

#include <algorithm>
#include <random>

std::random_device rd;
std::mt19937 mt(rd());

std::vector<Point> InitList(int M)
{
  if ( M <=0 )
    {
      std::cout << "InitList: Length of vector must be greater than zero. Don't play around!"
        << std::endl;
      exit(EXIT_FAILURE);
    }

  Point to_erase(-100,-100);    // <----- can I get rid of this?
  Point to_add;
  int x,y;
  std::vector<Point> vec = {}; 
  vec.push_back(to_erase);      // <----- and this
  
  while (vec.size() < M+1)      // <----- and then M+1 -> M
    {
      std::uniform_int_distribution<int> RandInt(0,100);
      x = RandInt(mt);
      y = RandInt(mt);
      point.set(x,y);
      if ( std::find(vec.begin(), vec.end(),to_add) == vec.end() )
    vec.push_back(to_add);
    }
  vec.erase (vec.begin());     // <----- and finally avoid this?
  return vec;  
}

How can I avoid the trick of adding the first instance to_erase ?如何避免添加第一个实例to_erase的技巧?

EDIT编辑

So I changed the implementation to use std::unordered_set and I am getting the following errors:因此,我将实现更改为使用std::unordered_set ,但出现以下错误:

error: use of deleted function ‘std::unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set() [with _Value = Site; _Hash = std::hash<Site>; _Pred = std::equal_to<Site>; _Alloc = std::allocator<Site>]’

note: ‘std::hash<Site>::hash()’ is implicitly deleted because the default definition would be ill-formed:
  101 |     struct hash : __hash_enum<_Tp>
      |            ^~~~
/usr/include/c++/9/bits/functional_hash.h:101:12: error: no matching function for call to ‘std::__hash_enum<Site, false>::__hash_enum()’
/usr/include/c++/9/bits/functional_hash.h:82:7: note: candidate: ‘std::__hash_enum<_Tp, <anonymous> >::__hash_enum(std::__hash_enum<_Tp, <anonymous> >&&) [with _Tp = Site; bool <anonymous> = false]’
   82 |       __hash_enum(__hash_enum&&);
      |       ^~~~~~~~~~~

And the list goes on.而这样的例子不胜枚举。 I guess there is an implementation missing in my class Point .我猜我的 class Point中缺少一个实现。 What should I do?我应该怎么办?

You can guarantee uniqueness just by using std::set ( https://www.cplusplus.com/reference/set/set/ ) instead of std::vector .您可以通过使用std::set ( https://www.cplusplus.com/reference/set/set/ ) 而不是std::vector来保证唯一性。

If order doesn't matter, use std::unordered_set .如果顺序无关紧要,请使用std::unordered_set

Regarding the hash issues you're seeing -- you have to define a hash function for a custom type, when using a few C++ types like set , unordered_set , map , etc. This is a function that returns a unique number based on the value of your custom Point instance. Regarding the hash issues you're seeing -- you have to define a hash function for a custom type, when using a few C++ types like set , unordered_set , map , etc. This is a function that returns a unique number based on the value您的自定义Point实例。 I stubbed out this example to give you an idea of how this might work for you, but YMMV:我删除了这个例子,让你了解这对你来说是如何工作的,但是 YMMV:

#include <iostream>
#include <unordered_set>

struct Point
{
  int x;
  int y;
  
  Point(int x, int y): x(x), y(y) {}; 
};

bool operator==(const Point& lhs, const Point& rhs)
{
    return ((lhs.x == rhs.x) and (lhs.y == rhs.y));
}

namespace std
{
    template <>
    struct hash<Point>
    {
        size_t operator()( const Point& p ) const
        {
            return (p.x << 32 | p.y);
        }
    };
}


int main() {
  
    Point p1(3,2);
    Point p2(3,2);
  
    std::unordered_set<Point> someSet;

    someSet.insert(p1);
    
    std::cout << "set size:" << someSet.size() << std::endl;
    // set size: 1
    
    someSet.insert(p2);

    std::cout << "set size:" << someSet.size() << std::endl;
    // set size: 1 (still!)

    return 0;
}

If only presence is relevant: std::set .如果只有存在是相关的: std::set

If you need also occurrence count, you could use std::map<Point, int> , where the int is the count.如果您还需要出现计数,则可以使用std::map<Point, int> ,其中int是计数。 With some special handling to remove elements when counts gets to zero.当计数为零时,通过一些特殊处理来删除元素。

You could replace std::map with std::unordered_map for performance reasons.出于性能原因,您可以将std::map替换为std::unordered_map But ALWAYS test both before deciding.总是在决定之前测试两者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM