【问题标题】:C++11 STL unique function, but in reverseC++11 STL 独特的功能,但相反
【发布时间】:2018-08-08 20:12:52
【问题描述】:

是否有类似std::unique 的函数,但它采用自定义比较谓词,并以等效顺序保留last 元素,而不是第一个?如果 C++14 或 C++17 是一个选项,答案是肯定的;但是我使用的是 C++11。

我从一个大型重物的双端队列开始,按一个轻量级字段排序。一些对象的轻量级字段具有相同的值,这是不可接受的。我需要丢弃除 last 对象以外的所有具有匹配光场的序列。

目前我的代码使用自定义二进制谓词和辅助重对象调用equal_range,然后倒回结束迭代器:

deque<Heavy> heavyDeque(...);

Light helperLight(...);
Heavy helperHeavy(helperLight, );

typedef deque<Heavy>:: iterator HevIt;

pair<HevIt, HevIt> deleteRange = equal_range(
    heavyDeque.begin(), heavyDeque.end(), helperHeavy,
    [](const Heavy & lhs, const Heavy & rhs) {
        return lhs.getLight() < rhs.getLight()})

//I have prior knowledge of at least one match
assert(deleteRange.first != deleteRange.second);
// back up; don't delete the last one
--(deleteRange.second);
heavyDeque.erase(deleteRange.first, deleteRange.second);

我对必须通过 helperHeavy 感到不太满意,而我需要的只是 helperLight。我宁愿我的代码看起来像这样:

pair<HevIt, HevIt> deleteRange = magical_range_search(
    heavyDeque.begin(), heavyDeque.end(),
    [helperLight](const Heavy & heavy) {
        return helperLight == heavy.getLight()})

请注意,我虚构的魔法函数采用 一元 谓词,而不是二元谓词。

【问题讨论】:

  • 使用反向迭代器?
  • 如果我理解正确,您想从超集中获取所有在超集中找到的所有集合的最后一个元素?
  • @KillzoneKid,看来我的编译器和 cplusplus.com 都告诉我 std::unique 只需要 ForwardIterators。
  • @ChristopherPisz 是的,总结正确。我想用最少的复制/移动操作来完成这个操作,因为对象很重。
  • @KevinHencke 我认为你误会了ideone.com/MgTzHd

标签: c++ iterator unique predicate deque


【解决方案1】:

大概是这样的吧?

template<typename BidirectionalIterator, typename UnaryPredicate>
pair<BidirectionalIterator,BidirectionalIterator>
magical_range_search(BidirectionalIterator begin,
                     BidirectionalIterator end, UnaryPredicate p)
{
  return {find_if(begin,end,p),
          find_if(make_reverse_iterator(end),make_reverse_iterator(begin),p)};
}

但是,当然,对于整个事情,您可以使用 std::uniquereverse_iterator,如 cmets 所示:

heavyContainer.erase(heavyContainer.begin(),
                     unique(make_reverse_iterator(heavyContainer.end()),
                            make_reverse_iterator(heavyContainer.begin()),
                            [](Heavy const&lhs, Heavy const&rhs) {
                                return lhs.getLight() < rhs.getLight();
                            }).base());

这里reverse_iterator&lt;&gt;::base() 返回unique() 返回的reverse_iterator 的底层原始迭代器。当unique() 返回序列的新结尾时,反向操作返回序列的新开始。新范围为{new_begin, orignal_end}{original_begin, new_begin} 范围内的元素必须为erase()d。

【讨论】:

  • 我喜欢您第二条建议的外观,但收到以下错误消息:错误:没有合适的用户定义转换来自 "std::reverse_iterator<:_deque_iterator heavy>>" 到 "const std::_Deque_iterator" 存在
  • 我正在尝试您的第一个建议;如果没有匹配,该解决方案会失效吗?我们会以 &*return.second
  • @KevinHencke 参考unique()reverse_iterator 的用法:在我的回答中解释返回的迭代器(reduced)时需要小心。很明显是reverse_iterator,所以不会自动转换成原来的迭代器类型,但是你可以使用base()。我会修改我的答案。
猜你喜欢
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
相关资源
最近更新 更多