【问题标题】:Is there a standard way to compare two ranges in C++?有没有一种标准方法来比较 C++ 中的两个范围?
【发布时间】:2011-07-21 06:49:03
【问题描述】:

范围是指一对迭代器。在伪 C++ 中:

std::vector<int> v1 = { 1, 2, 3, 4, 5 };
std::vector<int> v2 = { 2, 3, 4 };
if( std::compare_range( v1.begin() + 1, v1.end() - 1, v2.begin(), v2.end() ) {
    std::cout << "Alright\n";
}

compare_range 当然是我正在寻找的功能。

免责声明:我知道,这是一个非常简单的函数。但像所有程序员一样,我尽量偷懒;-)

【问题讨论】:

  • 比较如何?为了平等?等价?不等式?更高?降低?更热?更冷?更环保?更蓝? ...
  • @Tomalak Geret'kal:你忘了“更好”。

标签: c++ stl iterator


【解决方案1】:

std::equal 是您要查找的函数模板。

if (std::equal(v1.begin() + 1, v1.end() - 1, v2.begin())
{
    std::cout << "Alright\n";
}

注意std::equal 只接受三个参数,而不是四个。

【讨论】:

  • 不知何故错过了它。谢谢。现在我已经考虑过了,我显然不需要第四个参数...... :)
  • 这种方法很好,当用户保证两个间隔的长度相同时。否则它可能会崩溃或无法正常工作。
  • @Konstantin Tenzin:你的意思可能是“第二个间隔至少和第一个一样长”
  • @Alexander Poluektov:当第二个间隔大于第二个时,方法 std::equal 会将其限定为等于第一个:例如输入 {1,2,3}; {1,2,3,4}。某些应用程序可能不希望这样做
  • C++14增加4参数版本,不同长度范围返回false。
【解决方案2】:

使用std::equal - 它也支持范围。

【讨论】:

    【解决方案3】:

    似乎没有标准的“单一功能”方法。提到的 std::equal 假设第二个范围不比第一个短。例如,当第二个间隔为空时,这可能会导致内存损坏。当第二个范围较大时,它也不会给出答案。

    需要std::equal和std::distance的组合,或者自写函数:

    template <class InputIterator1, class InputIterator2>
    bool safe_equal( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2 )
    {
      return ( std::distance( first1, last1 ) == std::distance( first2, last2 ) )
         && std::equal( first1, last1, first2 );
    }
    

    对于非随机访问迭代器,上述函数可能会遍历容器两次,但使用标准函数。如果不可接受,编写自己的实现可能是合理的。

    【讨论】:

    • 小语法修复:最后一个参数必须称为last2 而不是second2&amp;&amp; 之后的第一个左括号是多余的。
    【解决方案4】:

    如果你有办法确定这两个范围有 完全相同数量的元素,std::equal 可以。在 练习,这对我来说似乎并不经常发生, 我对std::equal 的大部分用途实际上都是 确定一个范围是否是另一个范围的前缀。

    对于实际比较,我找到了std::lexicographical_compare 更有用,尽管它所承诺的关系是一种 顺序的,而不是等价的。为了等价,您可以应用它 两次,例如

       !lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())
    && !lexicographical_compare(b.begin(), b.end(), a.begin(), a.end())
    

    但这几乎意味着比较元素两次(除非 一开始就有区别)。

    【讨论】:

    • 这是非常数学和有见地的。当元素比较相对便宜,并且范围大小很昂贵(例如,只有前向迭代器)时——那么这个优雅的习惯用法就没有什么反对意见了。 (当然,std::equal 的 4 参数版本,它还会检查两个范围是否同时达到它们的 end(),仍然会更好)
    【解决方案5】:

    Boost 中有一个函数可以检查范围的大小:

    boost::range::equal
    

    【讨论】:

      【解决方案6】:

      使用 C++20:

      if (std::ranges::equal( std::ranges::subrange{ v1.begin() + 1, v1.end() - 1 }, v2) {
          std::cout << "Alright\n";
      }
      

      或者,如果需要 less/greater-check

      if (auto cmp = std::lexicographical_compare_three_way(v1.begin() + 1, v1.end() - 1, v2.begin(), v2.end()); cmp == 0) {
          std::cout << "Alright\n";
      }
      else if (cmp < 0) {//...}
      

      std::vector 是一个连续容器,因此STL 算法不需要额外的范围大小检查。

      【讨论】:

        猜你喜欢
        • 2013-04-16
        • 2021-09-13
        • 1970-01-01
        • 2011-01-21
        • 1970-01-01
        • 1970-01-01
        • 2012-06-15
        • 2021-04-17
        • 1970-01-01
        相关资源
        最近更新 更多