返回匹配条件的地图中的一组键

时间:2009-03-16 15:50:43

标签: c++ stl

首先,我将给出具体案例,我想看看它是否可以应用于一般问题。

说我有地图。我想让所有的钥匙符合一定的标准。 例如,包含“COL”的所有键。我天真的实施将是

template<typename T>
void  Filter (map<string, T> & m, std:set<string> & result, const std::string& condition)
{
    for(map<string,string> iter=m.begin();iter!m.end();iter++)
    {
           std::string key=iter->first; 
           size_t found=key.find(condition);
           if (found!=string::npos)
              result.insert(key);
    }     

}

实现这个的好方法是什么?

另外,当我想使用algos过滤地图时,实现一般问题的好方法是什么?

5 个答案:

答案 0 :(得分:1)

这似乎是remove_copy_if的候选人。我使用boost写了一些东西,看起来可能不仅仅是恶心,而是提供了算法的概括。

#include <boost/iterator/transform_iterator.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <algorithm>
#include <map>
#include <set>
#include <string>

struct filter_cond : std::unary_function<std::string, bool> {
    filter_cond(std::string const &needle):needle(needle) { }
    bool operator()(std::string const& arg) {
        return (arg.find(needle) == std::string::npos);
    }
    std::string needle;
};


int main() {
    std::set<std::string> result;
    typedef std::map<std::string, int> map_type;
    map_type map;

    std::remove_copy_if(
        boost::make_transform_iterator(map.begin(),
                                       boost::bind(&map_type::value_type::first, _1)),
        boost::make_transform_iterator(map.end(),
                                       boost::bind(&map_type::value_type::first, _1)),
        std::inserter(result, result.end()), 
        filter_cond("foo")
    );
}

我可能更喜欢手动循环。使用lambda表达式,C ++ 1x可以让它看起来更好。

答案 1 :(得分:0)

  

实现这个的好方法是什么?

看看下面。这是未经测试的东西,所以你可能需要修复它。

/* return some value */
/* fix order of input and output instead of having them mixed */
template<typename T>
size_t Filter(map<string, T> m, 
             string const& condition /* fixed condition; mark it as such */
             set<T>& result /* reference to add efficiency */
             )
{
  typename map<string, T>::const_iterator last = m.end();
  typename map<string, T>::const_iterator i = find_if(m.begin(),
                                             last,
                                             bind2nd(equal(), condition)
                                            );
  while (i != last) {
       result.insert(*i);
       i = find_if(i + 1,
                   last,
                   bind2nd(equal(), condition)
                   );
  }
  return result.size();

}

  

另外,当我想使用algos过滤地图时,实现一般问题的好方法是什么?

看看std::transform

答案 2 :(得分:0)

首先,一些非常小的建议:

  • 您可以缓存m.end()
  • 的值
  • 您可以使用++iter,它可以为您节省一份迭代器
  • 您可以通过将测试移动到一个非常明确命名的函数(如'KeyContainsSubstring(const std :: string&amp;)''或类似函数)来提高清晰度。

关于这类任务的更一般处理,我倾向于像你一样喜欢显式循环。无论如何,std :: map都没有提供更有效的密钥迭代机制。

备选方案包括std::for_each以及boost::bindboost::lambda

答案 3 :(得分:0)

我认为你的解决方案相当不错:很明显,除非你能根据条件“猜测”哈希值,否则我认为你的表现不会太高。但是,您可以更改功能以使其更通用:

template<typename TKey, typename TValue, typename Predicate>
void filter (const map<TKey, TValue> & m, 
             set<TKey> & result, 
             Predicate & p)
{
    typename map<TKey,TValue>::const_iterator it = m.begin();
    typename map<TKey,TValue>::const_iterator end = m.end();

    for( ; it != end ; ++it)
    {
        TKey key = it->first;
        if (p(key))
            result.insert(key);
    }     
}

然后可以使用仿函数作为谓词来编写您的示例:

struct Contains {
    Contains(const string & substr) : substr_(substr) {}

    bool operator()(const string & s)
    {
        return s.find(substr_) != string::npos;
    }

    string substr_;
};

对过滤器的调用将如下所示:

map<string, Obj> m;
// Insert in m
set<string> res;
filter(m, res, Contains("stringToFind"));

答案 4 :(得分:0)

你也可以这样做:

template<class T>
struct StringCollector
{
public:
    StringCollector(const std::string& str, std::set<std::string>& selectedKeys) : m_key(str), m_selectedKeys(selectedKeys)
    {

    }

    void operator()(const std::pair<std::string,T>& strPair_in)
    {
        size_t found = strPair_in.first.find(m_key);
        if(found != std::string::npos)
        {
            m_selectedKeys.insert(strPair_in.first);
        }
    }

private:
    std::set<std::string>& m_selectedKeys;
    std::string m_key;
};

在主叫代码中:

std::set<std::string> keys;
StringCollector<int> collector("String",keys);
std::for_each(a.begin(), a.end(), collector);