对范围排序-v3-压缩容器进行排序 - 我可以解压缩吗?

5

使用C++ Range-v3库,是否可以解压以前压缩的向量?我希望它的行为类似于Haskell的unzip函数或Python的zip(*list)

例如,在按另一个向量的值对向量进行排序时,这将非常方便:

using namespace ranges;

std::vector<std::string> names {"john", "bob", "alice"};
std::vector<int>         ages  {32,     19,    35};

// zip names and ages
auto zipped = view::zip(names, ages);
// sort the zip by age
sort(zipped, [](auto &&a, auto &&b) {
  return std::get<1>(a) < std::get<1>(b);
});
// put the sorted names back into the original vector
std::tie(names, std::ignore) = unzip(zipped);

1
函数的命名和命名空间让我觉得它不会创建一个新的数据结构。你确定它不是直接操作名称和年龄数据结构吗?如果是这样,解压将不会产生任何操作。 - stefan
@stefan 您说得对!如果我始终拥有所有原始的压缩向量,为什么我需要解压缩呢?我只是被不可变的 Haskell 列表搞混了。谢谢您,请您把它写成答案,这样我就可以标记为正确答案了。 - Floop
1个回答

10
当传递容器参数时,range-v3中的view::zip创建一个由对原始元素的引用组成的元组视图。将zipped视图传递给sort可以就地对元素进行排序。即,以下程序:
#include <vector>
#include <string>
#include <iostream>

#include <range/v3/algorithm.hpp>
#include <range/v3/view.hpp>

using namespace ranges;

template <std::size_t N>
struct get_n {
  template <typename T>
  auto operator()(T&& t) const ->
    decltype(std::get<N>(std::forward<T>(t))) {
      return std::get<N>(std::forward<T>(t));
  }
};

namespace ranges {
template <class T, class U>
std::ostream& operator << (std::ostream& os, common_pair<T, U> const& p) {
  return os << '(' << p.first << ", " << p.second << ')';
}
}

int main() {
  std::vector<std::string> names {"john", "bob", "alice"};
  std::vector<int>         ages  {32,     19,    35};

  auto zipped = view::zip(names, ages);
  std::cout << "Before: Names: " << view::all(names) << '\n'
            << "         Ages: " << view::all(ages) << '\n'
            << "       Zipped: " << zipped << '\n';
  sort(zipped, less{}, get_n<1>{});
  std::cout << " After: Names: " << view::all(names) << '\n'
            << "         Ages: " << view::all(ages) << '\n'
            << "       Zipped: " << zipped << '\n';
}

输出结果:

原始数据: 姓名:[john,bob,alice]
         年龄:[32,19,35]
       合并后: [(john, 32),(bob, 19),(alice, 35)]
 现在数据: 姓名:[bob,john,alice]
         年龄:[19,32,35]
       合并后: [(bob, 19),(john, 32),(alice, 35)]

Coliru上的实时示例.


确实。比起使用unzip更方便的是,一开始就让zip做正确的事情。:-) 感谢@Casey。 - Eric Niebler
我注意到有ranges::get,在这里找到。但它现在只接受一个范围,如果ranges::get也可以像上面的get_n一样接受元组,那就太好了。godbolt.org/g/QaiQQn - sandthorn
我无法编译此代码,请更新到最新的range-v3版本。 - Yen Dang
range-v3不再支持C++11,因此我更喜欢保留原始答案以供历史价值。https://godbolt.org/z/8KPebKx8E已更新为现代range-v3。 - Casey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接