Random element in a map

前端 未结 9 615
面向向阳花
面向向阳花 2021-01-07 16:14

what is a good way to select a random element from a map? C++. It is my understanding that maps don\'t have random access iterators. The key is a long long and the map is

相关标签:
9条回答
  • 2021-01-07 16:34

    I like James' answer if the map is small or if you don't need a random value very often. If it is large and you do this often enough to make speed important you might be able to keep a separate vector of key values to select a random value from.

    map<...> MyMap;
    vector<...> MyVecOfKeys; // <-- add keys to this when added to the map.
    
    map<...>::key_type key = MyVecOfKeys[ random_0_to_n(MyVecOfKeys.size()) ];
    map<...>::data_type value = MyMap[ key ];
    

    Of course if the map is really huge you might not be able to store a copy of all the keys like this. If you can afford it though you get the advantage of lookups in logarithmic time.

    0 讨论(0)
  • 2021-01-07 16:36
    map<...> MyMap;
    iterator item = MyMap.begin();
    std::advance( item, random_0_to_n(MyMap.size()) );
    
    0 讨论(0)
  • 2021-01-07 16:36

    Maybe you should consider Boost.MultiIndex, although note that it's a little too heavy-weighted.

    0 讨论(0)
  • 2021-01-07 16:41

    Here is the case when all map items must be access in random order.

    1. Copy the map to a vector.
    2. Shuffle vector.

    In pseudo-code (It closely reflects the following C++ implementation):

    import random
    import time
    
    # populate map by some stuff for testing
    m = dict((i*i, i) for i in range(3))
    # copy map to vector
    v = m.items()
    # seed PRNG   
    #   NOTE: this part is present only to reflect C++
    r = random.Random(time.clock()) 
    # shuffle vector      
    random.shuffle(v, r.random)
    # print randomized map elements
    for e in v:
        print "%s:%s" % e, 
    print
    

    In C++:

    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <vector>
    
    #include <boost/date_time/posix_time/posix_time_types.hpp>
    #include <boost/foreach.hpp>
    #include <boost/random.hpp>
    
    int main()
    {
      using namespace std;
      using namespace boost;
      using namespace boost::posix_time;
    
      // populate map by some stuff for testing
      typedef map<long long, int> Map;
      Map m;
      for (int i = 0; i < 3; ++i)
        m[i * i] = i;
    
      // copy map to vector
    #ifndef OPERATE_ON_KEY
      typedef vector<pair<Map::key_type, Map::mapped_type> > Vector;
      Vector v(m.begin(), m.end());
    #else
      typedef vector<Map::key_type> Vector;
      Vector v;
      v.reserve(m.size());
      BOOST_FOREACH( Map::value_type p, m )
        v.push_back(p.first);
    #endif // OPERATE_ON_KEY
    
      // make PRNG
      ptime now(microsec_clock::local_time());
      ptime midnight(now.date());
      time_duration td = now - midnight;
      mt19937 gen(td.ticks()); // seed the generator with raw number of ticks
      random_number_generator<mt19937, 
        Vector::iterator::difference_type> rng(gen);
    
      // shuffle vector
      //   rng(n) must return a uniformly distributed integer in the range [0, n)
      random_shuffle(v.begin(), v.end(), rng);
    
      // print randomized map elements
      BOOST_FOREACH( Vector::value_type e, v )
    #ifndef OPERATE_ON_KEY
        cout << e.first << ":" << e.second << " ";
    #else
        cout << e << " ";
    #endif // OPERATE_ON_KEY
      cout << endl;
    }
    
    0 讨论(0)
  • 2021-01-07 16:41
    std::random_device dev;
    std::mt19937_64 rng(dev());
    
    std::uniform_int_distribution<size_t> idDist(0, elements.size() - 1);
    auto elementId= elements.begin();
    std::advance(elementId, idDist(rng));
    

    Now elementId is random :)

    0 讨论(0)
  • 2021-01-07 16:43

    Maybe draw up a random key, then use lower_bound to find the closest key actually contained.

    0 讨论(0)
提交回复
热议问题