返回映射中符合条件的一组键

发布于 2024-07-14 22:49:36 字数 585 浏览 4 评论 0原文

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

说我有地图。 我想让所有的钥匙都满足一定的标准。 例如,所有包含“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);
    }     

}

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

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

First I will give a specific case, and the I would like to see if it can be applied to a general problem.

Say I have map. And I want to get all the keys meeting a certain criteria.
For example all keys that contain "COL". My naive implementation will be

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);
    }     

}

what is the good way to implement this?

Also, what is a good way to implement general problem when I want to filter map using algos?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

谜泪 2024-07-21 22:49:36

这看起来像是 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")
    );
}

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

That looks like a candidate for remove_copy_if. I've written something using boost that probably looks more than disgusting, but provides a generalization of your algorithm.

#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")
    );
}

I would probably prefer the manual loop. C++1x will make look that really much better with lambda expressions.

野却迷人 2024-07-21 22:49:36

我认为你的解决方案相当好:它很清楚,除非你可以根据条件“猜测”哈希值,否则我认为你的性能不会更高。 但是,您可以更改函数以使其更加通用:

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"));

I think your solution is rather good: it is clear, and except if you can "guess" hash values based on the condition, I don't think you could be much more performant. However, you could change your function to make it more generic:

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);
    }     
}

Your example can then be writen using a functor as predicate:

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

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

    string substr_;
};

The call to filter will then look like this:

map<string, Obj> m;
// Insert in m
set<string> res;
filter(m, res, Contains("stringToFind"));
献世佛 2024-07-21 22:49:36

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

看看下面。 不过,这是未经测试的东西,因此您可能需要修复它。

/* 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();

}

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

看一下 std::transform

what is the good way to implement this?

Take a look below. This is untested stuff though so you may need to fix it.

/* 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();

}

Also, what is a good way to implement general problem when I want to filter map using algos?

Take a look at std::transform.

无妨# 2024-07-21 22:49:36

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

  • 您可以缓存 m.end() 的值
  • 您可以使用 ++iter,它可以为您节省迭代器的一份副本
  • 您可以通过将测试移至非常明确命名的函数,例如 ''KeyContainsSubstring(const std::string&)'' 或类似函数。

在更一般地处理此类任务时,我实际上更喜欢像您一样的显式循环。 std::map 无论如何都没有提供更有效的键迭代机制。

替代方案包括 std::for_each 加上boost::bind,或boost::lambda

First, some very minor suggestions:

  • You could cache the value of m.end()
  • You could use ++iter, which saves you one copy of the iterator
  • You could improve clarity by moving the test to a very explicitely named function like ''KeyContainsSubstring(const std::string&)'' or similar.

On the more general handling of this sort of tasks, I tend to actually prefer explicit loops like you did. std::map does not provide a more efficient keys iteration mechanism anyway.

Alternatives would include std::for_each coupled with boost::bind, or boost::lambda.

街角迷惘 2024-07-21 22:49:36

您也可以这样做:

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);

You can also do it like this:

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;
};

In the calling code:

std::set<std::string> keys;
StringCollector<int> collector("String",keys);
std::for_each(a.begin(), a.end(), collector);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文