【问题标题】:How can I sort a vector based on sort of another vector?如何根据另一个向量的排序对向量进行排序?
【发布时间】:2020-03-14 17:09:55
【问题描述】:

我有四个要相互排序的向量。

vector<string> color;
vector<string> shape;
vector<int> size;

每个向量的大小相同,每个向量元素相互关联,从而形成一行

{color[0], shape[0], size[0]}
{color[1], shape[1], size[1]}
{color[2], shape[2], size[2]}, etc

所以我要做的是按颜色对颜色向量进行排序,并根据重新排列的颜色向量对其他两个向量进行排序。然后在每组颜色(即红色)中,我想按形状排序并根据该排序重新排列大小向量。最后我想对每组颜色和形状中的大小向量进行排序。我想我知道该怎么做,但是感觉非常混乱且难以概念化/阅读(我还是 C++ 新手)。有没有简单的方法来完成这样的事情?

例如我想做这样的事情:

Blue    Circle      1   ->    Red   Triangle    1           
Red     Triangle    1   ->    Red   Triangle    2
Blue    Circle      3   ->    Red   Triangle    3
Red     Triangle    3   ->    Red   Circle      1
Red     Circle      2   ->    Red   Circle      2
Blue    Triangle    1   ->    Red   Circle      3
Red     Circle      1   ->    Blue  Triangle    1
Blue    Triangle    3   ->    Blue  Triangle    2
Red     Circle      3   ->    Blue  Triangle    3
Blue    Circle      2   ->    Blue  Circle      1
Blue    Triangle    2   ->    Blue  Circle      2
Red     Triangle    2   ->    Blue  Circle      3

【问题讨论】:

  • 您应该创建一个Shape 类或结构,然后创建一个std::vector&lt;Shape&gt;,然后您可以按颜色对其进行排序。
  • 谢谢,我会调查的。这也能让我像我的例子那样做一个级联排序吗?
  • “级联”排序将仅取决于您的比较运算符。可以在std::tuple 上观察到您想要的排序示例(请参见示例代码):en.cppreference.com/w/cpp/utility/tuple/operator_cmp

标签: c++ sorting vector


【解决方案1】:

就像John 指出的那样,您应该制作一个struct,然后制作一个std::vector,然后您可以按颜色对其进行排序。这是一个解决方案:

#include <iostream>
#include <vector>
#include <algorithm> 
#include <cctype> 

struct MyStruct
{
    std::string color;
    std::string shape;
    int size;

    MyStruct(std::string co, std::string sh, int si): 
        color{co}, shape{sh}, size{si} {};
};

bool MyComp(MyStruct a,MyStruct b)
{ 
    auto f = [](unsigned char c){ return std::tolower(c);};
    std::transform(a.color.begin(), a.color.end(), a.color.begin(),f);
    std::transform(b.color.begin(), b.color.end(), b.color.begin(),f);

    return (a.color < b.color); 
}

int main() {

    std::vector<MyStruct> MyVec;

    MyVec.emplace_back("Blue","Circle",1); 
    MyVec.emplace_back("Red","Triangle",1);  
    MyVec.emplace_back("Blue","Circle",3);
    MyVec.emplace_back("Red","Triangle",3);   
    MyVec.emplace_back("Red","Circle",2);  
    MyVec.emplace_back("Blue","Triangle",1);   
    MyVec.emplace_back("Red","Circle",1);   
    MyVec.emplace_back("Blue","Triangle",3);   
    MyVec.emplace_back("Red","Circle",3);  
    MyVec.emplace_back("Blue","Circle",2);  
    MyVec.emplace_back("Blue","Triangle",2);   
    MyVec.emplace_back("Red","Triangle",2);

    std::sort(MyVec.begin(), MyVec.end(), MyComp);

    for(auto s : MyVec)
        std::cout << s.color << " " << s.shape  << " " << s.size << std::endl; 

    return 0;
}

You can run the code online 查看以下输出:

Blue Circle 1
Blue Circle 3
Blue Triangle 1
Blue Triangle 3
Blue Circle 2
Blue Triangle 2
Red Triangle 1
Red Triangle 3
Red Circle 2
Red Circle 1
Red Circle 3
Red Triangle 2

【讨论】:

    【解决方案2】:

    您应该创建一个Shape 类或结构,然后创建一个std::vector&lt;Shape&gt;,然后您可以首先按颜色排序,然后是其他参数。您定义了一个重载的operator&lt;,以便std::sort 函数可以找到它。

    看起来像这样:

    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <tuple>
    #include <vector>
    
    struct Shape
    {
        std::string color_;
        std::string shape_;
        int size_;
    
        Shape(const std::string& color, const std::string& shape, int size)
            : color_(color)
            , shape_(shape)
            , size_(size)
        {}
    
        // returns true if this shape is less than the other shape
        // "less than" is up to us: here we give priority to color, then shape, then size
        bool operator<(const Shape& other) const
        {
            // std::tie makes lexicographical compare of complex structures easy!
            return (std::tie(color_, shape_, size_) <
                    std::tie(other.color_, other.shape_, other.size_));
        }
    
        friend std::ostream& operator<<(std::ostream& os, const std::vector<Shape>& shapes)
        {
            for (auto& shape : shapes)
            {
                os << shape.color_ << " " << shape.shape_ << " " << shape.size_ << "\n";
            }
    
            return os;
        }
    };
    
    int main(int argc, char** argv)
    {
        std::vector<Shape> shapes;
    
        shapes.emplace_back("Blue", "Circle", 1);
        shapes.emplace_back("Red", "Triangle", 1);
        shapes.emplace_back("Blue", "Circle", 3);
        shapes.emplace_back("Red", "Triangle", 3);
        shapes.emplace_back("Red", "Circle", 2);
        shapes.emplace_back("Blue", "Triangle", 1);
        shapes.emplace_back("Red", "Circle", 1);
        shapes.emplace_back("Blue", "Triangle", 3);
        shapes.emplace_back("Red", "Circle", 3);
        shapes.emplace_back("Blue", "Circle", 2);
        shapes.emplace_back("Blue", "Triangle", 2);
        shapes.emplace_back("Red", "Triangle", 2);
    
        std::cout << "Pre sorted vector:\n";
        std::cout << shapes;
    
        // std::sort by default will use the operator< for the types
        // being sorted, if it's available
        std::sort(shapes.begin(), shapes.end());
    
        std::cout << "\nPost sorted vector:\n";
        std::cout << shapes;
    }
    

    这给出了输出:

    Pre sorted vector:
    Blue Circle 1
    Red Triangle 1
    Blue Circle 3
    Red Triangle 3
    Red Circle 2
    Blue Triangle 1
    Red Circle 1
    Blue Triangle 3
    Red Circle 3
    Blue Circle 2
    Blue Triangle 2
    Red Triangle 2
    
    Post sorted vector:
    Blue Circle 1
    Blue Circle 2
    Blue Circle 3
    Blue Triangle 1
    Blue Triangle 2
    Blue Triangle 3
    Red Circle 1
    Red Circle 2
    Red Circle 3
    Red Triangle 1
    Red Triangle 2
    Red Triangle 3
    

    【讨论】:

    • 有一个漂亮的(至少对我来说)比较器功能的单行器:return std::tie(color_, shape_, size_) &lt; std::tie(other.color_, other.shape_, other.size_);
    • 我喜欢这样。不知道std::tie
    【解决方案3】:

    第一个解决方案

    解决问题的一种方法是对向量进行排序,而是生成一个新的索引向量,我们将其命名为I,这样位于j 位置的项目在排序后的向量在当前未排序向量中的位置I[j]

    通过使用递增值0 .. n-1 对其进行初始化并使用自定义比较函数对向量进行排序,很容易生成此索引向量:

    std::vector<int> I(N);
    std::iota(begin(I), end(I), 0);
    std::sort(begin(I), end(I), [&](int ia, int ib) { return color[ia] < color[ib]; });
    // this is a simplified comparison function to not clutter the code
    

    现在,如果您想访问按color 排序的序列中第三个元素的shape,请编写:

    auto shape3 = shape[I[3]];
    

    第二种解决方案

    第一个解决方案有效,但由于多种原因可能不符合您的喜好。当您按升序遍历项目时,也许您不喜欢它随机化内存访问(以及相关的惩罚)这一事实。或者您可能真的需要对向量进行排序,因为您必须将它们传递给另一个组件。

    在这种情况下,您仍然可以使用第一种方法作为第一步,然后根据刚刚计算的索引对向量重新排序。以下是shape 向量重新排序的示例:

    std::vector<std::string> tmp_shape;
    tmp_shape.reserve(N);
    for(int j=0; j<N; ++j)
        tmp_shape.emplace_back(std::move(shape[I[j]]));
    shape.swap(tmp_shape);
    

    显然你需要为这三个向量保持它们的关系。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-05
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多