我有两张地图,我想得到的地图是仅使用键作为比较器的两个交点,同时对常见元素的值进行简单的数学运算,例如+/-
例如:
map<int, double> m1,m2;
m1[1] = 1.1;
m1[2] = 2.2
m2[2] = 0.1;
m2[4] = 3.3;
交叉后我会得到m3,如果我使用减法运算符,它将具有对:(2,2.1)。
使用算法库的有效方法是什么?
谢谢。
答案 0 :(得分:4)
我们希望在此功能中执行哪些操作?
然后我们必须考虑除了std :: map之外的其他容器是否适合这个模型。您想要包含多重映射并将所有元素与相同的键组合在一起(假设不是)?地图不必排序,因此散列图也应该有效。不幸的是,没有STL概念包括地图和哈希图,但没有包含多图。因此,让我们做一个:独特的对关联容器。我们的功能应该适用于这两种类型。
template <typename UPAC, // UPAC models Unique Pair Associative Container
typename BF> // BF models Binary Function on UPAC::value_type
UPAC combine_upacs(const UPAC& c1, const UPAC& c2, BF func) {
UPAC result;
typename UPAC::const_iterator it1 = c1.begin();
while (it1 != c1.end()) {
typename UPAC::const_iterator it2 = c2.find(it1->first);
if (it2 != c2.end())
result.insert(make_pair(it1->first, func(it1->second,it2->second));
++it1;
}
return result;
}
现在,如果您担心merge_upacs在std :: map上的运行时间,您可能希望利用映射进行排序的事实,并迭代c1和c2。但这是解决问题的最通用的代码。
答案 1 :(得分:3)
你可以分两步完成。第一个是找到交集,可以使用set_intersection算法完成。第二步将使用transform算法使用提供的仿函数进行数学运算。
我发现set_intersection
不允许提供访问函数,因此在下面的代码中有一个懒惰的替代品。我写了一个样本函子,它会为你做减法。我相信你可以轻松编写所有其他的仿函数。你也可以编写与set_intersection
做同样的模板函数,但允许提供将取消引用迭代器的函子。
// sample functor for substruction
template<typename T1, typename T2>
struct sub
{
// it will be better to use const references, but then you'll not be able
// to use operator[], and should be use `find` instead
sub( std::map<T1, T2>& m1, std::map<T1, T2>& m2 ) : m1(m1), m2(m2) {}
std::pair<T1,T2> operator()( const T1& index )
{ return make_pair( index, m1[index]-m2[index] ); }
private:
std::map<T1, T2>& m1, & m2;
};
int main()
{
map<int, double> m1,m2;
m1[1] = 1.1;
m1[2] = 2.2;
m2[2] = 0.1;
m2[4] = 3.3;
vector<int> v; // here we will keep intersection indexes
// set_intersection replacement
// should be moved to stand alone function
map<int, double>::const_iterator begin1 = m1.begin();
map<int, double>::const_iterator begin2 = m2.begin();
for (; begin1 != m1.end() && begin2 != m2.end(); ) {
if ( begin1->first < begin2->first ) ++begin1;
else if (begin2->first < begin1->first) ++begin2;
else v.push_back( begin1->first ), ++begin1, ++begin2;
}
map<int, double> m3;
transform( v.begin(), v.end(), std::inserter(m3, m3.begin()), sub<int, double>( m1, m2 ) );
}
答案 2 :(得分:0)
我不知道这样做的标准算法,但编写一个很简单。这适用于有序和无序地图。
template <class MapT, typename OperationT>
void intersect_maps(const MapT &map1, const MapT &map2, MapT &target, OperationT op) {
const MapT *m1, *m2;
// Pick the smaller map to iterate over
if (map1.size() < map2.size()) {
m1 = &map1;
m2 = &map2;
} else {
m1 = &map2;
m2 = &map1;
}
typename MapT::const_iterator it_end = m1->end();
for (typename MapT::const_iterator it = m1->begin(); it != it_end; ++it) {
typename MapT::const_iterator pos = m2->find(it->first);
if (pos != m2->end()) {
if (m1 == &map1) {
target.insert(typename MapT::value_type(it->first, op(it->second, pos->second)));
} else {
// we swapped the inputs so we need to swap the operands
target.insert(typename MapT::value_type(it->first, op(pos->second, it->second)));
}
}
}
}
double sub(double v1, double v2) {
return v1 - v2;
}
// And use it.
m1[1] = 1.1;
m1[2] = 2.2;
m2[2] = 0.1;
m2[4] = 3.3;
intersect_maps(m1, m2, m3, sub);