【问题标题】:Using a predicate to sort according to size使用谓词按大小排序
【发布时间】:2017-08-11 20:38:15
【问题描述】:

我知道谓词从迭代器的输入范围中获取参数并按预期执行操作,但是当我们提供二元谓词和一对迭代器时,它是如何工作的?容器的元素如何传递给谓词?

例如std::sort 默认按字母顺序对字符串向量进行排序,但要根据大小对它们进行排序,我们可以传递如下谓词:

sort(vec.begin(), vec.end(), [](const string &a, const string &b) {
    return a.size() < b.size();
});

所以,这应该按大小而不是按字母顺序对字符串向量vec 进行排序,但我无法理解这是如何发生的,即谓词如何将向量的元素作为参数以及它是如何发生的排序?

【问题讨论】:

  • 谓词不排序任何东西,它只是比较两个元素。 std::sort 根据需要调用谓词来比较各种元素对,以确定它们应该放置的顺序。

标签: c++ sorting stl predicate


【解决方案1】:

当调用 std 排序时,这个函数的“普通”版本将使用operator&lt; 执行一些比较。正如您所理解的,两个字符串之间的比较是按字典顺序进行的(就像字典一样)。 但是,开发std::sort 功能的人会考虑以下情况:

  1. 没有operator&lt;
  2. 用户可能需要另一种排序方式

这就是谓词有用的地方。谓词(如 Igor Tandetnik 所说)在 std::sortfunction 内部调用。

所以,对于普通版本,std::sort 会做类似的事情:

if(*a < *b) {
...
}

在谓词版本中,它的作用几乎相同:

if(predicate(*a, *b)) {
...
}

这样,您的谓词替换 operator&lt; 函数。

【讨论】:

    【解决方案2】:

    二元谓词只不过是一个可调用对象(包括函数或 lambda),它需要两个参数类型为容器的解引用迭代器类型。它的“作用”是为排序算法提供一个比较标准。

    std::sort 算法期望此函数或函数对象返回一个可转换为 bool 的值,并且当且仅当第一个参数在排序顺序中位于第二个参数之前(所谓的 严格的弱秩序)。然后,std::sort 算法通过在单独比较元素时将谓词应用于元素,对给定的对象范围(从容器开始到结束)进行操作(排序)。

    在您的情况下,如果容器是字符串向量,则取消引用的迭代器会产生 std:string,因此您的 lambda 可以正常工作。

    这里是一些示例代码,展示了它如何与独立于具体类型的 lambda 一起工作,但至少需要在容器中的对象上定义 size() 操作。它还显示了如何将二进制谓词作为函数对象提供(在这种情况下,我通过反转谓词来恢复排序顺序):

    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <vector>
    
    using Words = std::vector<std::string>;
    
    struct CompareReverse
    {
        bool operator() (auto lhs, auto rhs)
        {
            return rhs.size() < lhs.size(); // less-than reversed!
        }
    };
    
    int main()
    {
        Words words { "red", "green", "blue", "wizard", "a", "letter", "very-long-word" };
    
        std::sort(words.begin(), words.end(), [](auto a, auto b) { return a.size() < b.size(); });
    
        for (auto w : words)
            std::cout << w << std::endl;
    
        std::sort(words.begin(), words.end(), CompareReverse());
    
        for (auto w : words)
            std::cout << w << std::endl;
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多