How to sort vector of objects by a private string variable alphabetically

一曲冷凌霜 提交于 2020-01-03 22:26:46

问题


I cannot figure out how to sort a vector of objects by one of the member variables called VIN, which is of data type string. I am to either perform a bubble sort or a selection sort. I am most familiar with a bubble sort, so that's the direction I attempted to take. However, I am aware that I need to compare both of the strings by either making them all uppercase or lower case. Keep in mind, the strings also will have number characters in them as well.

So my question is: 1) How to I convert a string either all lowercase or all ASCII numbers and 2) What data type should the temp variable be (data type of the class or some other data type).

Here is the (incomplete) code I have so far:

    void sortInventory(vector<Vehicle> &carList)
    {
        bool swap; 
        string temp; 
        do
        {
            swap = false;

            for (int count = 0; count < carList.size(); count++)
            {
                if (carList[count].getVIN() > carList[count + 1].getVIN())
                {
                    temp = carList[count].getVIN();                                 
                    carList[count].getVIN() = carList[count + 1].getVIN();          
                    carList[count + 1].getVIN() = temp;                      
                    swap = true;                                               
                }
            }

        } while (swap);
}

Here is my class declaration:

class Vehicle
{
private:
    string VIN;

public:
    string getVIN();
    void   setVIN(string);

};

Here is my class implementation:

string Vehicle::getVIN()
{   return VIN;     }

void Vehicle::setVIN(string input)
{   VIN = input;    }

Thanks!


回答1:


You can do std::sort(carList.begin(),carList.end(),vehicleCompare) where vehicleCompare is a comparison function that you define. See sort documentation. Then, to uppercase you can use std::toupper, as shown in this guide.

std::string myToUpper(std::string in) {
    std::transform(in.begin(), in.end(),in.begin(), ::toupper);
    return in;
}

So the comparison operator(*) will be:

bool vehicleCompare (const Vehicle a, const Vehicle b) {
    const std::string a_name = myToUpper(a.getVIN());
    const std::string b_name = myToupper(b.getVIN());
    return (a_name < b_name);
    }

Useful reading about string comparison operator.

By the way, your string getVIN() method should be const, that is you should change its declaration to string getVIN() const.

If you want to keep your sorting function, the point is that in any case you'll have to define a proper comparison operator, as the one shown here.


To specifically answer to your second question, temp could be auto in C++11, or simply std::string. Then the way you are trying to assign your VIN value is wrong. Given the interface you have given, it should be:

auto temp = carList[count].getVIN();                                 
carList[count].setVIN(carList[count + 1].getVIN() );          
carList[count + 1].setVIN(temp);

Although it still might get nasty when you start to have more than one member variable to copy: you should instead build a copy constructor and change your code to:

auto temp = carList[count]; //you can use Vehicle instead of auto as type
carList[count] = carList[count + 1];          
carList[count + 1] = temp;

The copy constructor will be:

Vehicle(const Vehicle& in) 
  : VIN(in.getVIN() ) 
  {}

And, at that point, you'll also want a constructor from string, and an empty constructor.

Vehicle(std::string& inVIN) 
  : VIN(inVIN) 
  {}

Vehicle(const Vehicle& in) 
  {} //All input members get initialized through the default constructor.


(*) Note that this comparison method wouldn't be the most efficient, as it makes uppercase the whole string while the first few characters are normally sufficient to decide their order. So a more efficient way would be to uppercase one character at the time and compare it before deciding if to uppercase another character.


回答2:


Answer to question 1: You can make a simple function that converts a std::string to upper.

void string_to_upper(string &s) {
  for(int l = 0; l < s.length(); ++l) {
     s[l] = toupper(s[l]);
  }
}



回答3:


First, your Vehicle::getVIN() method should be marked as const, to implement proper const-correctness:

string Vehicle::getVIN() const
{
    return VIN;   
}

Then, note that you don't need to reinvent the wheel and reimplement a sorting algorithm from scratch in production code in C++ (unless this is a learning exercise/homework about writing sorting code).

You can simply use the standard std::sort() algorithm implemented in the STL, and customize the comparison criteria using a convenient C++11 lambda, e.g.:

// std::vector<Vehicle> carList;

std::sort(carList.begin(), carList.end(), 
    [](const Vehicle& v1, const Vehicle& s2)
    {
        /* Code implementing custom Vehicle comparison */
    }
);

Your code in the lambda could be something like this:

    [](const Vehicle& v1, const Vehicle& s2)
    {
        // Use stricmp() to compare strings in a case insensitive way
        return (stricmp(v1.getVIN().c_str(), v2.getVIN().c_str()) < 0);
    }

Instead of calling stricmp(), you can use boost::to_upper(), or some other method among the ones showed e.g. in this thread on StackOverflow:

Case insensitive string comparison in C++



来源:https://stackoverflow.com/questions/29907135/how-to-sort-vector-of-objects-by-a-private-string-variable-alphabetically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!