首先,我将给出具体案例,我想看看它是否可以应用于一般问题。
说我有地图。我想让所有的钥匙符合一定的标准。 例如,包含“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过滤地图时,实现一般问题的好方法是什么?
答案 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过滤地图时,实现一般问题的好方法是什么?
答案 2 :(得分:0)
首先,一些非常小的建议:
++iter
,它可以为您节省一份迭代器关于这类任务的更一般处理,我倾向于像你一样喜欢显式循环。无论如何,std :: map都没有提供更有效的密钥迭代机制。
备选方案包括std::for_each
以及boost::bind
或boost::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);