只对向量中的一个类成员进行排序,其他成员保持不变

Sort just one member of the classes in a vector, leaving the other members unchanged

本文关键字:成员 排序 其他 向量 一个      更新时间:2023-10-16

有大量的答案可以对成员变量的结构向量进行排序。使用std::sort和谓词函数,比较结构成员很容易。真的很容易。

但我有一个不同的问题。假设我有以下结构:

struct Test {
int a{};
int b{};
int toSort{};
};

以及该结构的向量,例如:

std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };

我不想对向量元素进行排序,而只想对成员变量中的值进行排序。因此,预期输出应等于:

std::vector<Test> tvSorted{ {1,1,5},{2,2,6},{3,3,7},{4,4,8},{5,5,9} };

我希望解决方案在某种程度上是一个通用解决方案。然后我想出了一个(抱歉(预处理器宏解决方案。请参阅以下示例代码:

#include <iostream>
#include <vector>
#include <algorithm>
struct Test {
int a{};
int b{};
int toSort{};
};
#define SortSpecial(vec,Struct,Member) 
do { 
std::vector<decltype(Struct::Member)> vt{}; 
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [](const Struct& s) {return s.Member; }); 
std::sort(vt.begin(), vt.end()); 
std::for_each(vec.begin(), vec.end(), [&vt, i = 0U](Struct & s) mutable {s.Member = vt[i++]; }); 
} while (false)
int main()
{
// Define a vector of struct Test
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "n";
// Call sort macro
SortSpecial(tv, Test, toSort);
std::cout << "nnSortedn";
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "n";
}


由于宏不应该在C++中使用,所以我的问题在这里:

1. 算法库的解决方案是否可行?

2. 或者这可以通过模板实现吗?

将当前解决方案转换为模板解决方案相当简单。

template <typename T, typename ValueType>
void SpecialSort(std::vector<T>& vec, ValueType T::* mPtr) {
std::vector<ValueType> vt;
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T& s) {return s.*mPtr; });
std::sort(vt.begin(), vt.end());
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable {s.*mPtr = vt[i++]; });
}

我们可以通过传入向量和指向成员的指针来调用它。

SpecialSort(tv, &Test::toSort);

像这样(如果需要,您只需要复制、重命名和编辑其余变量的"switchToShort"功能(:

#include <iostream>
#include <vector>
struct Test {
int a{};
int b{};
int toSort{};
};
void switchToShort(Test &a, Test &b) {
if (a.toSort > b.toSort) {
int temp = a.toSort;
a.toSort = b.toSort;
b.toSort = temp;
}
}
//void switchToA(Test& a, Test& b) { ... }
//void switchToB(Test& a, Test& b) { ... }
inline void sortMemeberValues(std::vector<Test>& data, void (*funct)(Test&, Test&)) {
for (int i = 0; i < data.size(); i++) {
for (int j = i + 1; j < data.size(); j++) {
(*funct)(data[i], data[j]);
}
}
}
int main() {
std::vector<Test> tv { { 1, 1, 9 }, { 2, 2, 8 }, { 3,3 ,7 }, { 4, 4, 6 }, { 5, 5, 5} };
sortMemeberValues(tv, switchToShort);
//sortMemeberValues(tv, switchToA);
//sortMemeberValues(tv, switchToB);
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "n";
}

使用 range-v3(很快范围为 C++20(,您可以简单地执行以下操作:

auto r = tv | ranges::view::transform(&Test::toSort);
std::sort(r.begin(), r.end());

演示