对 unordered_multimap 键进行平均的更好方法是啥?

Posted

技术标签:

【中文标题】对 unordered_multimap 键进行平均的更好方法是啥?【英文标题】:Is the a better way to do an average of a unordered_multimap key?对 unordered_multimap 键进行平均的更好方法是什么? 【发布时间】:2019-12-03 16:58:17 【问题描述】:

我正在我的 unordered_multimap 中搜索获取一个键的所有值,这实际上是堆叠一个 int 和一个表示执行时间(以纳秒为单位)的值。我需要用 一个平均键来替换多键的所有值。

我尝试了一些代码,这个实际上是最有价值的:

std::unordered_multimap<int, std::chrono::nanoseconds> data;
std::chrono::nanoseconds average;
// *filling my map with value*
for (auto & pair : data)
  auto range = data.equal_range(pair.first);

  for_each (
    range.first,
    range.second,
    [](std::unordered_multimap<int, std::chrono::nanoseconds>::value_type& x)
      average = average + x.second;
    
  );
  average = average / data.count(pair.first);
  data.erase(pair.first);
  data.insert(pair.first, average);
  

我得到的错误error: 'average' is not captured : average = average + x.second;

【问题讨论】:

我不明白这个问题。为什么不在更高的范围内声明average The problem is that average isn't defined out of the for_each loop - 所以在 for_each 循环中定义平均值。问题解决了! data.erasedata 的循环内:哎哟。 正如错误所说,您没有捕获average。将其添加到 lambda 的捕获列表中。 我做了更改并在更大范围内进行了声明,但仍然无法正常工作 【参考方案1】:

而不是std::for_each,使用std::accumulate

请注意,在 ranged-for 中从 std::unordered_multimap 中删除条目是未定义的行为。填充不同的容器更安全。

std::unordered_multimap<int, std::chrono::nanoseconds> data;
// *filling my map with value*

std::unordered_multimap<int, std::chrono::nanoseconds> new_data;
for (auto it = data.begin(); it != data.end(); ++it)
  auto range = data.equal_range(it->first);

  auto average = std::accumulate (
    range.first,
    range.second,
    std::chrono::nanoseconds0,
    [](auto sum, auto & x)
      return sum + x.second;
    
  ) / std::distance(range.first, range.second);

  new_data.emplace(key, average);

data.swap(new_data);

或者,如果你有 C++17,std::transform_reduce

  std::transform_reduce(
    range.first,
    range.second,
    std::chrono::nanoseconds0,
    std::plus<>,
    [](auto & x)  return x.second; 
  )

【讨论】:

我试过这个,但是有很多错误,根本无法编译 emplace 真的总是安全的吗?我想它不会导致重新散列,因为大小不会增加,但是新元素的迭代器是否保证在从erase 返回的it 之前排序? 效果很好,在你编辑后我确实改变了,一切都好!谢谢 @walnut 也许?之后填写decltype(data) new_data;data.swap(new_data); 可能更安全 @Caleth 是的,那是我的建议。还允许删除 erase 并使用普通的迭代器循环。仅根据 cppreference,因为 C++14 保证 erase 保留迭代器的顺序,并且在这方面它没有说明 emplace

以上是关于对 unordered_multimap 键进行平均的更好方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

保证 std::unordered_multimap 中的键唯一性

在 boost::unordered_multimap 中循环遍历 equal_range

如何拥有 unordered_multimaps 的 unordered_multimap

如何将现有模板类部分专门化为新类型?

使用 std::generate 的随机 unordered_multimap

如何在 C++ 中在 int 和 pair 之间制作 unordered_multimap?