マップからランダムな要素を選択する良い方法は何ですか? C++。私の理解では、マップにはランダムアクセス反復子がありません。キーは長く、マップはまばらに移入されます。
map<...> MyMap;
iterator item = MyMap.begin();
std::advance( item, random_0_to_n(MyMap.size()) );
マップが小さい場合や、ランダムな値があまり必要ない場合は、Jamesの回答が好きです。それが大きく、速度を重視するのに十分な頻度でこれを行う場合、ランダムな値を選択するためにキー値の個別のベクトルを保持できる可能性があります。
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 ];
もちろん、マップが非常に大きい場合、このようにすべてのキーのコピーを保存できない場合があります。対数時間でのルックアップの利点は得られますが、余裕があればできます。
おそらくランダムなキーを作成し、次に lower_bound を使用して、実際に含まれている最も近いキーを見つけます。
事前構築されたマップと高速ランダムルックアップのryan_sテーマを継続します。ベクトルの代わりに、反復子のパラレルマップを使用できます。これにより、ランダムルックアップが少し高速化されます。
map<K, V> const original;
...
// construct index-keyed lookup map
map<unsigned, map<K, V>::const_iterator> fast_random_lookup;
map<K, V>::const_iterator it = original.begin(), itEnd = original.end();
for (unsigned i = 0; it != itEnd; ++it, ++i) {
fast_random_lookup[i] = it;
}
// lookup random value
V v = *fast_random_lookup[random_0_to_n(original.size())];
マップが静的である場合、マップの代わりに、ベクターを使用してキーと値のペアをキー順に格納し、バイナリ検索で値をlog(n)時間でルックアップし、ベクターインデックスを使用して一定時間でランダムペアを取得します。ベクトル/バイナリ検索をラップして、ランダムアクセス機能を備えたマップのように見せることができます。
Boost.MultiIndex を検討する必要があるかもしれませんが、少し重すぎることに注意してください。
allマップアイテムにランダムな順序でアクセスする必要がある場合がこれにあたります。
疑似コード(次のC++実装を厳密に反映しています):
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
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;
}
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));
今elementIdはランダムです:)
誰かがこれを試しましたか? https://github.com/mabdelazim/Random-Access-Map "ランダムアクセスマップのC++テンプレートクラス。これはstd :: mapに似ていますが、my_map構文を使用してインデックスによってアイテムにランダムにアクセスできます.key(i)およびmy_map.data(i) "