【问题标题】:std::map - erase last elementstd::map - 擦除最后一个元素
【发布时间】:2012-06-21 17:07:44
【问题描述】:

我的地图是这样定义的: map<string, LocationStruct> myLocations; 其中key是时间字符串

我在这张地图中只保留了 40 件物品,当我达到 40 件物品时,我想放弃地图中的最后一件物品。我知道我做不到myLocations.erase(myLocations.end()),那我该怎么做呢?

我确实希望地图中的最后一项是最旧的,因此是 FIFO。数据将很快进入(大约 20Hz),所以我希望地图能跟上它。我确实需要根据时间查找数据,所以我确实需要它作为关键,但我愿意接受其他方法来实现这一点。

字符串的格式是一个非常冗长的“Thursday June 21 18:44:21:281”,但为了简单起见,我可以将其缩减为自纪元以来的秒数。这是我第一次尝试,还没有过多考虑格式。

【问题讨论】:

  • myLocations.erase(myLocations.rbegin()) 不会做这项工作吗?
  • 听起来,您想要某种固定长度的队列/优先级队列,而不是(排序的)地图。
  • @Rook map<>::erase 将迭代器而不是 reverse_iterator 作为其位置参数。
  • 您应该努力将日期/时间视为程序逻辑中的数字,并且仅将文本格式用于输入/输出目的。
  • 你的日期格式很不方便。 time_t 类型的秒格式会更容易使用。如果出于某种原因必须使用字符串格式,请使用(相对)健全且标准化的系统,如 ISO 8601,其中时间和字典排序顺序是相同的。

标签: c++ stl map erase


【解决方案1】:

最惯用的方式是:

myLocations.erase( std::prev( myLocations.end() ) );

如果您没有 C++11,请使用您的相应函数 工具箱。

【讨论】:

  • 假设字符串是按时间顺序而不是按字典顺序排序的
  • @MooingDuck 这就是他的要求:如何删除最后一个元素。
  • 问题已更新以澄清:“我确实希望地图中的最后一项是最旧的,因此是 FIFO。” “字符串的格式是非常冗长的'Thursday June 21 18:44:21:281'...”,鉴于该信息,此答案是错误的。
  • @MooingDuck 你似乎在自相矛盾。如果地图中的最后一项是最旧的,那么上述是正确的。字符串的格式真的无关紧要;正确处理它取决于地图的比较功能(尽管由于他担心速度,我会使用某种时间戳而不是字符串进行索引)。
  • 你似乎在建议他使用不同的容器类型。如果是这样,那应该是答案,而不是 cmets。 map<string, LocationStruct, comparitor>,附上比较器的写法说明。
【解决方案2】:

试试这个,它有效:

map<string, LocationStruct>::iterator it = myLocations.end();
it--;
myLocations.erase(it);

【讨论】:

  • 除非myLocations 的大小为零,但可能是假设这是给定的
【解决方案3】:

我假设当您说“擦除最后一个元素”时,您的意思是“擦除最旧的元素”。

我不会使用字符串作为时间,而是使用日期/时间类型(如 unix 时间戳)。然后它们将按时间排序,而不是按字典顺序排序,您可以myLocations.erase(myLocations.begin()),因为最旧的总是在开头。

更好的是,使用boost::circular_buffer&lt;std::pair&lt;timetype, LocationStruct&gt;&gt;,并使用std::lower_bound 按时间查找元素。这将自动为您删除最旧的,并且在按时间查找元素时具有相同的逻辑复杂度。添加数据时也更快。对于您的情况,这几乎是全赢的。如果您真的想避免使用boost,那么std::deque 最适合您的需求,并提供出色的性能,但如果您已经有一个可用的map,那么使用std::map 可能是最好的。

这是在deque 中查找的方法:

typedef ???? timetype;
typedef std::pair<Timetype, LocationStruct> TimeLocPair
typedef std::deque<TimeLocPair> LocationContainer;
typedef LocationContainer::const_iterator LocationIterator;

bool compareTimeLocPair(const TimeLocPair& lhs, const TimeLocPair& rhs)
{return lhs.first < rhs.first;}

LocationIterator find(const LocationContainer& cont, timetype time) {
    TimeLocPair finder(time, LocationStruct());
    LocationIterator it = std::lower_bound(cont.begin(), cont.end(), finder, compareTimeLocPair);
    if (it == cont.end() || it->first != time)
        return cont.end();
    return it;
}

【讨论】:

  • 这取决于字符串是如何存储的日期如果说时间不属于同一天,则必须注意日期,我在回答中提到了这一点
  • @Ritesh:那是我的本意,但根据您的困惑,我已经澄清了措辞并提供了示例类型。
  • @Jason,如果您不能或不想使用 Boost,std::deque 将替代 boost::circular_buffer。当 FIFO 达到最大大小时,只需在末尾删除元素。另外,请注意boost::circular_buffer 是一个仅限标头的库,我怀疑它会增加你的可执行文件的大小。实例化 boost::circular_buffer 模板可能会增加与实例化 std::deque 一样多的膨胀。
  • 为了帮助您做出决定,这里是circular_buffer 文档的基本原理部分:boost.org/doc/libs/release/libs/circular_buffer/doc/…
  • @MooingDuck:我想切换到deque 可能会被认为是过早的优化,如果他已经几乎可以使用map。但在内心深处,map 用于实现 FIFO 数据结构而不是 deque 让我很困扰。 :-)
【解决方案4】:

嗯,对 g++ 4.4 的快速检查表明这工作得很好:

myLocations.erase(myLocations.rbegin()->first);

虽然我必须承认我不知道为什么它不喜欢只接受迭代器本身。

【讨论】:

  • 即传递最后一个元素的key,传递给erase的key是有效的东西。与简单地将迭代器传递给最后一个元素相比,这很慢。
  • 因为rbegin返回一个reverse迭代器
  • 是的,我知道这一点。因此,为什么我实际上说“我不知道为什么它不喜欢只接受迭代器本身”
  • erase() 没有重载需要reverse_iterator,这就是原因。
  • 另外,很想知道为什么一个有效且语法正确的答案值得反对。毕竟,延迟迭代器的性能开销并不大。
【解决方案5】:

因为您将时间存储为 key String 。最后一个元素(考虑到从 00:00 到 24:00 的时间,一天中最早的时间)将是一个下界元素,因此您可以像这样获取迭代器

     `map<string, LocationStruct>::iterator it;`
      it=myLocations.lower_bound ('00:00');
      myLocations.erase ( it, it+1);

但是if it belongs to different dates 那么你甚至需要考虑这一天并相应地修改你的代码。正如您提到的data is coming quick enough,您不需要考虑日期。但是The safe way here would be take the entire date in terms of second and remove the lowest one as mentioned above。即使新数据到达的频率很慢,这也会引起注意。

【讨论】:

  • 仍然没有处理 23:59 之后是 00:01
  • @MooingDuck 这就是为什么我提到这里的安全方法是以秒为单位的整个日期并删除上面提到的最低日期
  • 重读您的答案,您是正确的,但之前的判决似乎与该建议相矛盾。如果您可以澄清您的措辞(并发表评论,以便我注意到),我将删除反对票。
【解决方案6】:

map::erase 对于没有 TS 绑定的最后一个元素,只需使用以下内容:

myLocations.erase ((--myLocations.end()));

【讨论】:

    猜你喜欢
    • 2013-09-12
    • 2011-10-23
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    相关资源
    最近更新 更多