[英]How can I sort a vector based on sort of another vector?
I have a four vectors that I want to sort in relation to each other.我有四个向量,我想对其进行排序。
vector<string> color;
vector<string> shape;
vector<int> size;
Each vector is the same size each vector element is tied to each other such that it forms a row每个向量的大小相同,每个向量元素相互关联,形成一行
{color[0], shape[0], size[0]}
{color[1], shape[1], size[1]}
{color[2], shape[2], size[2]}, etc
So what I am trying to do is sort the color vector by color and sort the other two vectors based on the rearranged color vector.所以我想要做的是按颜色对颜色向量进行排序,并根据重新排列的颜色向量对其他两个向量进行排序。 Then within every group of colors (ie red) I want to sort by shape and rearrange the size vector based on that sort.
然后在每组颜色(即红色)中,我想按形状排序并根据该排序重新排列大小向量。 And then finally I want to sort the size vector within each group of color and shape.
最后我想对每组颜色和形状中的大小向量进行排序。 I think I know how to do it but it feels very very messy and difficult to conceptualize/read (I'm still new to C++).
我想我知道该怎么做,但是感觉非常非常混乱并且难以概念化/阅读(我还是 C++ 的新手)。 Is there an easy way to accomplish something like this?
有没有一种简单的方法来完成这样的事情?
For example I want to do something like this:例如,我想做这样的事情:
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
Like John pointed out, you should make a single struct
, and then make a std::vector
, which you can then sort on color.就像约翰指出的那样,您应该制作一个
struct
,然后制作一个std::vector
,然后您可以对颜色进行排序。 Here is a solution:这是一个解决方案:
#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 to see the following output:您可以在线运行代码以查看以下输出:
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
You should make a single Shape
class or struct, and then make a std::vector<Shape>
, which you can then sort on color, primarily, followed by your other parameters.您应该创建一个
Shape
类或结构,然后创建一个std::vector<Shape>
,然后您可以对颜色进行排序,主要是对其他参数进行排序。 You define an overloaded operator<
so that the std::sort
function will find it.您定义了一个重载
operator<
以便std::sort
函数可以找到它。
It would look like this:它看起来像这样:
#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;
}
This gives the output:这给出了输出:
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
First solution第一个解决方案
One way to solve the problem is to not sort the vectors, but instead to produce a new vector of indexes, let's name it I
, such that the items at position j
in the sorted vectors are at position I[j]
in the current unsorted vectors.解决问题的一种方法是不对向量进行排序,而是生成一个新的索引向量,让我们将其命名为
I
,这样已排序向量中位置j
处的项目位于当前未排序中的位置I[j]
向量。
It is easy to produce this indexing vector by initializing it with the increasing values 0 .. n-1
and sorting the vector with a custom comparison function:通过使用递增值
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
Now if you want to access the shape
of the 3rd element in the sequence sorted by color
you write:现在,如果要访问按
color
排序的序列中第三个元素的shape
,请编写:
auto shape3 = shape[I[3]];
Second solution第二种解决方案
The first solution works, but it may not be to your liking for many reasons.第一个解决方案有效,但由于多种原因,它可能不符合您的喜好。 Maybe you don't like the fact that it randomizes memory accesses (and the associated penalty) when you walk the items in ascending order.
也许您不喜欢这样一个事实,即当您按升序遍历项目时,它会随机化内存访问(以及相关的惩罚)。 Or maybe you really need to sort the vectors because you have to pass them to another component.
或者您可能真的需要对向量进行排序,因为您必须将它们传递给另一个组件。
In that case, you can still use the first method as a first step, and then reorder the vectors based on the indexes just computed.在这种情况下,您仍然可以使用第一种方法作为第一步,然后根据刚刚计算的索引对向量重新排序。 Here is an example of such reordering for the
shape
vector:以下是对
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);
Obviously you need to do that for the three vectors to maintain their relationship.显然,您需要为三个向量执行此操作以保持它们的关系。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.