std :: find_if,std :: binary_function,用于按值搜索std :: map

时间:2014-01-20 13:43:11

标签: c++ c++11 lambda

我的std::map有一对'唯一键'和'唯一值'。我通常会找到一个值的键,并为键找到一个值。 我已经知道使用std::find_if + lambda的方法,但是我想知道是否有更好的方法。

搜索之后,我找到了this article,并且我学会了如何使用`std :: binary_function'。 使用这两种方法,我检查了'经过的时间'。 这是我的代码。

typedef int                                 USER_ID;
typedef std::string                         USER_NICK_NAME;
typedef std::map<USER_ID, USER_NICK_NAME>   USER_MAP;

template<class T>
struct map_data_compare : public std::binary_function<typename T::value_type, typename T::mapped_type, bool>
{
  public:
  bool operator() (typename T::value_type &pair, typename T::mapped_type i) const
  {
    return pair.second == i;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{
  USER_MAP user_map;
  string nick_prefix = "test";

  //make test map
  for (int i = 0; i < 100000; i++)
  {
    std::ostringstream stream;
    stream << i;
    user_map.insert(USER_MAP::value_type(i, nick_prefix + stream.str()));
  }

  const USER_NICK_NAME nick_name = "test99999";
  clock_t t;

  //Method 1 : using find_if + lambda
  cout << "Method 1 : using find_if + lambda" << endl;
  t = clock();
  auto it = std::find_if(user_map.begin(), user_map.end(), [&](const USER_MAP::value_type& user)
  {
    return nick_name == user.second;
  });
  if (it != user_map.end())
  {
    cout << "found nickname " << nick_name.c_str() << ", at index " << it->first << endl;
  }
  t = clock() - t;
  cout << "elapsed " << ((float)t)/CLOCKS_PER_SEC << " seconds" << endl;

  cout << endl << endl;

  //Method 2 : using find_if + binary_function
  cout << "Method 2 : using using find_if + binary_function" << endl;
  t = clock();
  it = std::find_if(user_map.begin(), user_map.end(), std::bind2nd(map_data_compare<USER_MAP>(), nick_name));
  if (it != user_map.end())
  {
    cout << "found nickname " << nick_name.c_str() << ", at index " << it->first << endl;
  }
  t = clock() - t;
  cout << "elapsed " << ((float)t)/CLOCKS_PER_SEC << " seconds" << endl;

  return 0;
}

在我的机器中,方法1 始终比方法2 更快。 这是测试结果控制台。 enter image description here

所以,我的问题是,

  1. 在我的情况下(我的意思是按值搜索地图),find_if + lambda是最好的方法吗? (不幸的是,我不能使用boost库。)
  2. 当我使用std::binary_function
  3. 我知道在C ++ 11中,`std :: binary_function'已被弃用。我能知道原因吗?
  4. 感谢您抽出时间查看此主题并尝试提供帮助。

2 个答案:

答案 0 :(得分:1)

假设您具有透明比较的C ++ 1y功能,您可以创建std::set std::map::iterator .second.second字段排序,并使比较器透明,以便您可以通过std::map字段的类型在其中进行查找。

但这不太可能。

如果你没有这个,并且你可以使你的值字段(合理地)便宜复制,你可以从值字段到迭代器的std::unordered_mapstd::map到{{1 }}。假设您需要在主地图中同时查找顺序。

如果您不需要订购,请停止使用map

typedef std::unordered_map< int, std::string > main_map;
typedef std::unordered_map< std::string, int > backwards_map;

然后将上面的内容包装在一些样板中以保持两者同步。

请注意unordered_map迭代器是非持久的。 std::map迭代器是高度持久的。因此,对于双unordered案例,向后地图是不同的。

对于binary_functionbind2nd,不推荐使用。

答案 1 :(得分:1)

  

在我的情况下(我的意思是按值搜索地图),find_if + lambda是最好的方法吗?

这当然是最好的方式(假设您不能使用第二张地图,或者可能是升压式多索引地图,以快速查找值)。原则上,使用等效仿函数和/或bind不应该明显更慢,这里唯一的区别是nick_name是通过值而不是引用来捕获的;也许您还没有启用优化,或者您的编译器可能没有优化bind2nd以及人们可能希望的优化。

  

当我使用std::binary_function

从历史上看,如果您不想自己定义别名,那么您将继承它以将类型别名(first_argument_typesecond_argument_typeresult_type)注入您的仿函数中。这些有时是必需的,例如当使用bind2nd之类的适配器(也已弃用)来创建基于您的函数的新仿函数。

  

我知道在C ++ 11中,std::binary_function已被弃用。我能知道原因吗?

它定义的类型对于bind这样的新式可变参数适配器既不必要也不够,所以它不再有用了。