【问题标题】:Sort just one member of the classes in a vector, leaving the other members unchanged只对向量中的一个类成员进行排序,其他成员保持不变
【发布时间】:2019-12-21 18:26:48
【问题描述】:

关于成员变量的结构向量排序有很多答案。使用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 << "\n\nSorted\n";
    for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}


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

1.有没有算法库的解决方案?

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

【问题讨论】:

    标签: c++ sorting vector struct


    【解决方案1】:

    将您当前的解决方案转换为模板解决方案非常简单。

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

    【讨论】:

    • 非常好的解决方案。而且确实直截了当。谢谢。 +1 + 接受
    【解决方案2】:

    有点像这样(如果需要,您只需复制、重命名和编辑其余变量的“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";
    }
    

    【讨论】:

      【解决方案3】:

      使用range-v3(很快将在 C++20 中使用 ranges),您可以简单地这样做:

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

      Demo

      【讨论】:

      • 也是很好的答案。这是使用新 C++20 功能的版本。甚至比模板更好,+1。但目前我仍在使用 C++17 并且仅使用标准库。
      猜你喜欢
      • 2015-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      相关资源
      最近更新 更多