【问题标题】:How to sort vector of objects by a private string variable alphabetically如何按字母顺序按私有字符串变量对对象向量进行排序
【发布时间】:2015-07-06 13:53:16
【问题描述】:

我不知道如何通过名为 VIN 的成员变量之一对对象向量进行排序,该成员变量的数据类型为 string。我要么执行冒泡排序,要么执行选择排序。我最熟悉冒泡排序,所以这就是我试图采取的方向。但是,我知道我需要通过将它们全部设为大写或小写来比较这两个字符串。请记住,字符串中也会包含数字字符。

所以我的问题是: 1)如何将字符串转换为全小写或全ASCII数字和 2)临时变量应该是什么数据类型(类的数据类型或其他一些数据类型)。

这是我目前拥有的(不完整的)代码:

    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);
}

这是我的班级声明:

class Vehicle
{
private:
    string VIN;

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

};

这是我的类实现:

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

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

谢谢!

【问题讨论】:

    标签: c++ sorting object vector


    【解决方案1】:

    您可以使用std::sort(carList.begin(),carList.end(),vehicleCompare),其中vehicleCompare 是您定义的比较函数。见sort documentation。然后,可以使用std::toupper转大写,如this guide所示。

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

    所以比较运算符(*) 将是:

    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);
        }
    

    关于string comparison operator 的有用阅读。

    顺便说一句,你的string getVIN()方法应该是const,也就是说你应该把它的声明改为string getVIN() const

    如果你想保留你的排序功能,关键是在任何情况下你都必须定义一个适当的比较运算符,就像这里显示的那样。


    为了具体回答您的第二个问题,temp 在 C++11 中可以是 auto,或者只是 std::string。那么您尝试分配 VIN 值的方式是错误的。鉴于您给出的界面,它应该是:

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

    虽然当你开始复制多个成员变量时它仍然可能会变得很糟糕:你应该构建一个复制构造函数并将你的代码更改为:

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

    复制构造函数将是:

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

    而且,此时,您还需要一个来自字符串的构造函数和一个空构造函数。

    Vehicle(std::string& inVIN) 
      : VIN(inVIN) 
      {}
    
    Vehicle(const Vehicle& in) 
      {} //All input members get initialized through the default constructor.
    


    (*) 请注意,这种比较方法不是最有效的,因为它使整个字符串大写,而前几个字符通常足以决定它们的顺序。因此,一种更有效的方法是同时将一个字符大写并在决定是否将另一个字符大写之前进行比较。

    【讨论】:

    • 这是一个非常昂贵的比较函数,因为它通常可以在比较第一个字符后确定。
    • @BenjaminLindley 是的,但我认为 OP 的水平远未准备好进行优化。我认为首先向他展示如何分而治之更重要。无论如何,我已经在答案中添加了注释。
    【解决方案2】:

    问题 1 的答案:您可以创建一个简单的函数,将 std::string 转换为大写。

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

    【讨论】:

      【解决方案3】:

      首先,您的 Vehicle::getVIN() 方法应标记为 const,以实现正确的 const 正确性:

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

      然后,请注意,您无需重新发明轮子并在 C++ 生产代码中从头开始重新实现排序算法(除非这是关于编写排序代码的学习练习/家庭作业)。

      您可以简单地使用在 STL 中实现的标准 std::sort() 算法,并使用方便的 C++11 lambda 自定义比较标准,例如:

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

      您在 lambda 中的代码可能是这样的:

          [](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);
          }
      

      除了调用stricmp(),您还可以使用boost::to_upper(),或显示的其他方法,例如在 StackOverflow 上的这个线程中:

      Case insensitive string comparison in C++

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-04
        • 1970-01-01
        • 2012-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多