匹配地图而不重新创建

时间:2015-08-31 15:54:53

标签: c++ dictionary key assignment-operator

说我有两个map。这些map的值相同,构造起来很昂贵(不能复制)。这些map的键具有不同的类型,但可以相互转换。我需要设置第一个map的内容以匹配第二个map的内容,但我必须一直循环遍历int。有没有办法做到这一点?

作为一个例子,我已经将关键字简化为可识别的可转换的东西,并且仅使用foo s作为值。在示例中,我想设置bar的内容以匹配map的内容。但是我无法在没有遍历map<int, int> foo = {{1, 100}, {2, 200}, {4, 400}}; map<char, int> bar = {{'1', 200}, {'3', 300}, {'5', 500}}; for(auto i = foo.begin(); i != foo.end(); ++i) { if(bar.end() == bar.find(static_cast<decltype(bar)::key_type>(i->first) + '0')){ foo.erase(i); } } for(auto i = bar.begin(); i != bar.end(); ++i) { const decltype(foo)::key_type key = i->first - '0'; if(foo.end() == foo.find(key) || foo[key] != i->second) { foo[key] = i->second; } } for(const auto i : foo){ cout << i.first + 10 << ": " << i.second << endl; } 的情况下找到办法。

map

这正确输出:

  11:200
  13:300
  15:500

[Live Example]

有没有办法做到这一点,不需要循环通过public class MySpringActuatorMetricsCoreTestInterceptor extends SpringBeanAutowiringInterceptor { //Spring boot application context @Autowired ApplicationContext applicationContext; @SuppressWarnings("resource") @Override protected BeanFactory getBeanFactory(Object target) { return applicationContext.getAutowireCapableBeanFactory(); } } 两个?

2 个答案:

答案 0 :(得分:1)

如果不检查每个集合的每个元素,就无法同步两个集合。所以你将不得不迭代两个集合。

但是如果集合以相同的顺序键入,那么您可以通过并行和合并迭代两个集合来加快速度。如果您的标准库具有emplace_hint的有用实现,那么这将特别有效。

基本伪代码(意思是它不会编译并且可能无法正常工作:-))。

/* Makes a into a copy of b, assuming that the key types are
 * consistently comparable, and that a key for a can be constructed
 * from a key for b.
 */
void merge(Map1& a, Map2& b) {
  auto it_a = a.begin(), end_a = a.end();
  auto it_b = b.begin(), end_b = b.end();
  for (;;) {
    if (it_a == end_a) {
      /* Add remaining elements from b to a */
      for (; it_b != end_b; ++it_b)
        a.emplace_hint(it_a, it_b->first, it_b->second);
      return;
    } else if (it_b == end_b) {
      /* Remove remaining elements from a */
      while (it_a != end_a)
        it_a = a.erase(it_a);
      return;
    } else if (it_b->first < it_a->first) {
      /* Insert an element from b */
      a.emplace_hint(it_a, it_b->first, it_b->second);
      ++it_b;
    } else if (it_b->first == it_a->first) {
      /* Replace an element from b */
      a->second = b->second;
      ++it_a, ++it_b;
    } else {
      /* Delete element from a */
      it_a = a.erase(it_a);
    }
  }
}

注意:上面的代码如果可以覆盖现有值,则不必过度地构造新值,但它并没有真正避免构造值,因为它可能会破坏一个值与a中不需要的密钥相关联,然后构造与a中不存在的密钥关联的值。如果复制构造比赋值更昂贵,那么保留构造值池可能是有意义的,代价是向映射值添加间接。 shared_ptr是另一种可能性,尽管它也可能过度。

答案 1 :(得分:0)

使用boost transformed适配器,您可以简单地使用带有两个迭代器的std::map构造函数,并以更不容易出错,更直接的方式实现相同的功能:

using namespace boost::adaptors;
auto transformed_map = 
    bar | transformed([](const std::pair<const char, int>& p) {
        return std::make_pair(p.first - '0', p.second);
    });

foo = std::map<int, int>(std::begin(transformed_map),
                         std::end(transformed_map));

我发现上面的内容更容易理解。

现在,如果你发现自己做了很多,并且建设成本太高,这可能表明设计问题更大。也许您想要存储shared_ptr<value_type>而不是value_type。或者你可能只想做一些事情:

struct two_maps {
    std::map<int, int> foo;

    auto from_foo(int k) { return foo.find(k); }
    auto from_bar(char k) { return foo.find(k - '0'); }
};