【问题标题】:Order a vector according to weights stored in another vector using STL algorithms使用 STL 算法根据存储在另一个向量中的权重对向量进行排序
【发布时间】:2021-09-21 07:51:26
【问题描述】:

我有一个包含类实例的向量,比如说std::vector<A> a。我想根据存储在std::vector<float> weights 中的权重对这个向量进行排序,weights[i] 是与a[i] 关联的权重;排序后,a 元素必须按权重递增排序。

我知道如何明确地做到这一点,但我想使用 C++14 STL 算法以便从最终的最佳实现中受益。到目前为止,我还没有弄清楚如何在std::sort 的 lambda 比较表达式中使用weights,也无法弄清楚每次交换a 的两个元素时如何保持a 和weights 对齐by std::sort,所以我开始认为这可能是不可能的。

提前感谢您的帮助。

【问题讨论】:

  • 您还想遵守什么 C++ 标准? (C++14?然后使用那个标签。)你可以使用 Range-v3 和/或 Boost 之类的库吗?
  • 只是一个想法,我正在忙着提款机。您可以尝试压缩这两个向量,按元组的权重成员对结果向量进行排序,将其他结果转换为仅考虑元组的 A 成员。使用范围会更简单。

标签: c++ c++14


【解决方案1】:

对一个索引向量进行排序,然后根据结果重新排列:

void my_sort(std::vector<A>& a, std::vector<float>& weights)
{
  std::vector<int> idx(a.size());
  std::iota(idx.begin(), idx.end(), 0);
  sort(idx.begin(), idx.end(),
     [&](int a, int b) { return weights[a] < weights[b]; });

  auto reorder = [&](const auto& o) {
     decltype(o) n(o.size());
     std::transform(idx.begin(), idx.end(), n.begin(),
         [&](int i) { return o[i]; });
     return n;
  };
  a = reorder(a);
  weights = reorder(weights);
}

【讨论】:

  • 这个独立的解决方案效果很好(在修复了由于错误的自动类型导致的几个编译错误之后)!谢谢!
【解决方案2】:
  1. 在 std::pair 向量中转换两个向量,然后根据权重(对的第二个成员)进行排序。之后重新创建这两个向量
  2. 向 A 类添加一个新成员,使其包含权重并根据该权重排序
  3. 根据包含此处所述权重的全局数组创建自定义比较函数:std::sort and custom swap function

我会选择 3,因为它是最有效的。如果您没有需要同步的多线程,这是有效的。

【讨论】:

    【解决方案3】:

    我的评论是指@AndreaRossini 在他们的评论中总结的内容。像这样的:

    #include <boost/hana/functional/on.hpp>
    #include <functional>
    #include <iostream>
    #include <range/v3/algorithm/sort.hpp>
    #include <range/v3/view/transform.hpp>
    #include <range/v3/view/zip.hpp>
    #include <string>
    #include <vector>
    
    using boost::hana::on;
    using namespace ranges;
    using namespace ranges::views;
    
    // helpers to get first and second of a pair
    auto /*C++17->*/constexpr/*<-C++17*/ fst = [](auto const& p){ return p.first; };
    auto /*C++17->*/constexpr/*<-C++17*/ snd = [](auto const& p){ return p.second; };
    
    int main(){
        std::vector<std::string> v{"one", "two", "three"}; // values
        std::vector<float> w{3,1,2};                       // weights
    
        // zipping the two sequences; each element of vw is a pair
        auto vw = zip(v, w);
    
        // sorting: using `std::less` on the `snd` element of the pairs
        sort(vw, std::less<>{} ^on^ snd);
    
        // extracting only the `fst` of each pair
        auto res = vw | transform(fst);
    
        // show result
        for (auto i : res) { std::cout << i << std::endl; }
    }
    

    关于我使用过的库的一些信息:

    • res 不是 std::vector 而只是 view;如果你想要一个向量,你可以做
      #include <range/v3/range/conversion.hpp>
      auto res = vw | transform(fst) | to_vector;
      
    • std::less&lt;&gt;{} ^on^ snd 等价于以下f
      auto f = [](auto const& x, auto const& y){
          return std::less<>{}(snd(x), snd(y));
      };
      
      所以你可以把它想象成一个接受x和y并返回snd(x) &lt; snd(y)的函数。

    【讨论】:

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