按多个值对向量进行排序

Posted

技术标签:

【中文标题】按多个值对向量进行排序【英文标题】:Sort vector by multiple values 【发布时间】:2014-01-20 00:53:00 【问题描述】:

我必须对向量进行排序。该向量包含指向“学生”类对象的指针。

评分指标如下所示:

    最好的最终成绩 如果最终成绩相同,则尝试次数更少 如果相同的尝试,更少的 id 0 次尝试的学生比 2 次尝试和期末 5 的学生差,将 0 次尝试的学生按较少的 id 排序

学生长这样:

private:
std::string name_;
int id_;
int attempts_;  //max 2, if 0, exam not taken
int grade1_;
int grade2_;
int finalGrade_;  // grade 5 for failed exam but still better than 0 attempts in rating

我的问题是我不知道如何处理尝试。因为最佳尝试次数是 1 次,并且比 2 次尝试次数要好。但 2 次尝试在评分中优于 0。

我希望你能理解我的问题并能帮助我。谢谢 :)

【问题讨论】:

您需要一种不同类型的容器,它可能是一个多映射或您有一个键和一个值的东西。 @user2485710:这不是真的,sort 可以采用任意复杂的比较函数。 @BenVoigt 我不认为sort 可以很好地处理多个字段,可能你想要一个稳定的排序。无论如何,我认为向量是错误的数据结构。 @user2485710:规则似乎防止出现平局(平局由 ID 打破,这可能是唯一的),因此排序的稳定性无关紧要。 @user2485710:问题已经说了。请注意,平局最终会出现在排序级别 3 和 4 中,它们会被 ID 打破。 【参考方案1】:

在 STL 中有一个可用的函数,称为 std::sort,它可以采用比较器函数(函数指针或函数对象)。

比较器函数必须返回一个布尔值,说明第一个元素是否应该严格出现在第二个元素之前。

这是我想出的比较器:

struct compare_student 
    inline bool 
    operator() (Student *left, Student *right) const
    
        if(left->attempts_ == 0 && right->attempts_ == 0)
            return left->id_ < right->id_;
        else if(left->attempts_ == 0)
            return false;
        else if(right->attempts_ == 0)
            return true;

        return 
            left->finalGrade_ <  right->finalGrade_ ||    // Compare final grade
            left->finalGrade_ == right->finalGrade_ && (  // If final grade same:
                left->attempts_ <  right->attempts_ ||    // Compare attempts
                left->attempts_ == right->attempts_ && (  // If attempts same:
                    left->id_ < right->id_                // Compare id's
                )
            );
    
;

显然,您的所有字段都是私有的,因此您需要使用它们的访问器方法,而不是直接访问它们,但以下是您的使用方法:

vector<Student *> students ...;
std::sort(students.begin(), students.end(), compare_student);

std::sort 不稳定,这意味着如果两个元素被认为是相等的,那么它们不一定会保持它们的相对顺序,这对你来说可能很重要。如果是,那么还有一个名为std::stable_sort的函数确实有这样的保证,并且使用方式完全相同:

std::stable_sort(students.begin(), students.end(), compare_students);

编辑 实施说明

compare_students 是一个只有一个公共成员的类,所以不要这样做:

class compare_student 
public:
    ...
;

我把它缩短为:

struct compare_student 
    ...
;

(两者在 C++ 中是等价的,struct 只是一个具有默认公共访问权限的类。)

那么inline bool operator()是什么意思。

inline是给编译器的一个提示,这个函数可以内联,也就是说,用代码本身替换调用。 bool 是函数的返回类型。

operator() 是函数的名称,它是一个特殊情况的函数,当您将对象视为函数时会调用它:

Student *a, *b;
compare_student comparator ;

comparator(a, b); // calls comparator::operator()(a, b)

【讨论】:

谢谢,我在家的时候试试这个。只是几个问题。我需要“struct”吗?“inline bool operator()”是什么意思?到目前为止,当我编写排序函数时,我只是编写了 bool sortSomething(Student *k, Student *j) ... 然后将此比较函数用作 stl::sort 函数中的第三个参数 thx buddy @d0zer:比较不需要存储任何状态,所以一个独立的函数非常好,更容易。我也不会使用这个答案显示的巨大的|| == &amp;&amp; 链。但是 asQuirrel 给了你一个很大的线索。 @d0zer 根据是否经常使用比较器,函数对象比函数指针更便于内联。如果这不是问题,那么是的,函数指针也一样好。附言用您留下的评论的解释更新了答案。 嘿,出差了,没时间看这个。我在哪里创建该结构?在我的学生班级内? @d0zer,切换0次尝试相关的return true和return false。【参考方案2】:

听起来你的比较函数的第一行应该是

if (left.attempts_ == 0)

从那里检查是否还有right.attempts_ == 0。如果是,请检查 ID。

如果没有,那么右边有一个档次,左边没有,右边更好。

继续执行其余规则。最终,您可以使用 if (left.attempts_ &lt; right.attempts_) 之类的规则,但前提是您已经处理了 0 次尝试。

【讨论】:

我在您和 asQuirreL 的帮助下解决了这个问题。唯一的问题是,首先显示的是尝试次数为 0(最差指标)的学生。然后在那些尝试 0 次之后,排序是正确的。我怎样才能把那些尝试次数为 0 的人放在最后?

以上是关于按多个值对向量进行排序的主要内容,如果未能解决你的问题,请参考以下文章

按多个键值对数据进行排序

按多个条件对向量进行排序

在 Symfony2 中按多个值对数据库中的记录进行排序

按特定键的内部数组的值对PHP二维数组进行排序[重复]

我有不同的类,我想用这些类中的对象制作一个向量并按值对其进行排序

如何按值对 LevelDB 进行排序