2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

unorderd_mapをまとめて削除

Posted at

unorderd_mapにはerase_return_voidってのがあります。
もともと、quick_eraseという関数名だったのですが変更になったようです。

STLのeraseは削除した要素の次のイテレータを返すんですが、
unorderd_mapの場合、次のイテレータを求めるコストってのがあるらしく
何も返さないeraseであればその分速く出来るようです。

eraseの返り値を使うのは条件に合う要素をまとめて消す場合だと思います。
以下のような、ややわかりにくいコードで知られていると思います。

# include<vector>

int main(){
	std::vector<int> v;
	for (auto it = v.begin(); it != v.end();){
		if (*it % 4 == 0){
			it = v.erase(it);
		}else{
			it++;
		}
	}
}

こういうのをunorderd_mapでやる場合、どうすればいいか、ということで、
ベンチマークを取ってみました。

データを乱数で突っ込んでおいて、keyが4の倍数の要素だけ消すベンチマークです。

erase1は、vector等でも使われる、eraseで次のイテレータを受け取る形式です
erase2は、条件をまとめておいて、keyを指定してのeraseです。
erase3は、erase_return_voidを使ったやつです。

erase2,3は削除するキー分のバッファが必要ですし、毎回findの必要もあります。

# include <iostream>
# include <vector>
# include <string>
# include <boost/unordered_map.hpp>
# include <boost/timer/timer.hpp>

bool check(int n) { return n % 4 == 0;}

void erase1(boost::unordered_map<int, int *> &map)
{
	for (auto it = map.begin(); it != map.end();) {
		if (check(it->first)) {
			it = map.erase(it);
		}
		else {
			it++;
		}
	}
}

void erase2(boost::unordered_map<int, int *> &map)
{
	std::vector<int> keyvec;

	for (const auto &v : map) {
		if (check(v.first))keyvec.push_back(v.first);
	}

	for (int key : keyvec) {
		map.erase(key);
	}
}

void erase3(boost::unordered_map<int, int *> &map)
{
	std::vector<int> keyvec;

	for (const auto &v : map) {
		if (check(v.first))keyvec.push_back(v.first);
	}

	for (int key : keyvec) {
		auto it = map.find(key);
		map.erase_return_void(it);
	}
}


void speed_check(std::function<void()> func)
{
	boost::timer::auto_cpu_timer timer;

	func();

}

int main()
{
	boost::unordered_map<int, int *> map1, map2, map3;

	int value = 0;

	for (int i = 0; i < 100000; i++) {
		int key = rand();

		map1[key] = &value;
		map2[key] = &value;
		map3[key] = &value;
	}

	speed_check([&]() {erase1(map1); });
	speed_check([&]() {erase2(map2); });
	speed_check([&]() {erase3(map3); });


    return 0;
}

wandbox

そして実行結果は…ドン!

 0.012342s wall, 0.010000s user + 0.000000s system = 0.010000s CPU (81.0%)
 0.025197s wall, 0.030000s user + 0.000000s system = 0.030000s CPU (119.1%)
 0.023067s wall, 0.020000s user + 0.000000s system = 0.020000s CPU (86.7%)

無理にerase_return_voidを使うよりは、普通にループした方が倍以上速いですね。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?