简体   繁体   中英

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 .

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 ?

EDIT

So I changed the implementation to use std::unordered_set and I am getting the following errors:

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 . What should I do?

You can guarantee uniqueness just by using std::set ( https://www.cplusplus.com/reference/set/set/ ) instead of std::vector .

If order doesn't matter, use 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. I stubbed out this example to give you an idea of how this might work for you, but 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 .

If you need also occurrence count, you could use std::map<Point, int> , where the int is the count. With some special handling to remove elements when counts gets to zero.

You could replace std::map with std::unordered_map for performance reasons. But ALWAYS test both before deciding.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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