简体   繁体   中英

Sorting a std::vector of struct's in ascending order

Suppose that we have a struct and a std::vector , defined as:

struct example { 
   int x;       
   int height;
   std::string type; 
};

std::vector<example> objects;

First of all, we sort objects in ascending order, based on values of x , which can be implemented pretty easy:

std::sort(objects.begin(), objects.end(), [](const example &a, const example &b) {
    return a.x < b.x;
});

But if values of x are the same, There are three conditions need to be handled based on other properties. Consider the following as our objects:

x:0,height:3,type:"start"
x:7,height:11,type:"start"
x:5,height:8,type:"end"
x:1,height:4,type:"start"
x:3,height:6,type:"start"
x:4,height:7,type:"start"
x:1,height:5,type:"start"
x:5,height:9,type:"end"
x:7,height:12,type:"end"
x:6,height:10,type:"start"

After insertion, I sort them based on values of x using the code written above, and the result would look like this:

x:0,height:3,type:"start"
x:1,height:4,type:"start"
x:1,height:5,type:"start"
x:3,height:6,type:"start"
x:4,height:7,type:"start"
x:5,height:8,type:"end"
x:5,height:9,type:"end"
x:6,height:10,type:"start"
x:7,height:11,type:"end"
x:7,height:12,type:"start"

Now there are modifications I need to do to the above vector (which is sorted based on values of x , only.

Condition 1 : If values of x and type are the same, and the type equals to start , the object with the larger height must come before.

Condition 2 : If values of x and type are the same, and the type equals to end , the object with the smaller height must come before.

Condition 3 : If values of x are the same and the values of type are not, the object with start type must come before.

So, the final sorted vector should look like this:

x:0,height:3,type:"start"
x:1,height:5,type:"start"
x:1,height:4,type:"start"
x:3,height:6,type:"start"
x:4,height:7,type:"start"
x:5,height:8,type:"end"
x:5,height:9,type:"end"
x:6,height:10,type:"start"
x:7,height:12,type:"start"
x:7,height:11,type:"end"

How these conditions can be implemented?

Instead of writing just return ax < bx; , insert all your conditions. What is important to notice is that the expression ax < bx evaluates to a boolean value: true or false. If the expression is true, the first element(in this case a), will come first in the sorted array.

You could create your conditions as such:

if(a.x == b.x) {
    if(a.type.compare(b.type) == 0){ //the types are equal
        //condition one
        if(a.type.compare("start") == 0) {
            return a.height > b.height;
        }
        //condition two
        if(a.type.compare("end") == 0) {
            return a.height < b.height;
        }
    }
    else { //types are not equal, condition three
        if(a.type.compare("start") == 0) //the type of a is start
            return true;
        else
            return false;
    }
}
else {
    return a.x < b.x;
}

It would be a good idea to put this code in a compare function:

bool compare(const exampleStruct& a, const exampleStruct& b)
{
    //the code written above
}

And call the std::sort as:

std::sort(objectVector.begin(), objectVector.end(), compare);

It's pretty straight forward. Just follow the logic in your comparator:

std::sort(objectVector.begin(), objectVector.end(), [](exampleStruct a, exampleStruct b) {
    if (a.x != b.x)
        return a.x < b.x;

    // a.x == b.x

    if (a.type == b.type)
    {
        if (a.type == "start")
            return a.height > b.height;
        if (a.type == "end")
            return a.height < b.height;

        throw std::invalid_argument("invalid type");
    }

    // a.x == b.x && a.type != b.type

    if (a.type == "start")
        return true;
    if (b.type == "start")
        return false;

    throw std::invalid_argument("invalid type");
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM