簡體   English   中英

如何根據另一個向量的排序對向量進行排序?

[英]How can I sort a vector based on sort of another vector?

我有四個向量,我想對其進行排序。

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

就像約翰指出的那樣,您應該制作一個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;
}

您可以在線運行代碼以查看以下輸出:

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

您應該創建一個Shape類或結構,然后創建一個std::vector<Shape> ,然后您可以對顏色進行排序,主要是對其他參數進行排序。 您定義了一個重載operator<以便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

第一個解決方案

解決問題的一種方法是不對向量進行排序,而是生成一個新的索引向量,讓我們將其命名為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);

顯然,您需要為三個向量執行此操作以保持它們的關系。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM