C++ 使用 <algorithm> 对向量的向量进行分区
C++ Partition a vector of vectors using <algorithm>
假设您有一个二维向量定义如下:
std::vector<vector<int>> v
其中代表一个矩阵:
1 1 0 1 3
0 4 6 0 1
5 0 0 3 0
6 3 0 2 5
我想稳定分区(比如使用谓词 el != 0)这个矩阵,但是在所有方向上。这意味着我希望能够得到:
1 1 6 1 3 0 0 0 0 0 1 1 1 3 0 0 1 1 1 3
5 4 0 3 1 1 1 0 1 3 4 6 1 0 0 0 0 4 6 1
6 3 0 2 5 5 4 0 3 1 5 3 0 0 0 0 0 0 5 3
0 0 0 0 0 6 3 6 2 5 6 3 2 5 0 0 6 3 2 5
(down) (up) (right) (left)
对于两个方向,这可以非常简单地通过迭代外部向量并划分内部向量(按顺序或反向)来完成。但是对于其他方向,我不知道如何去做同样的事情。
有没有办法使用 std::stable_partition
实现此目的?是否有另一种数据结构(支持像向量一样的索引)可以让我更容易地做到这一点?
如果我有 ti 从头开始实施,是否有标准或推荐的方法来做到这一点?
您不需要编写自己的算法实现。当您想要将现有算法用于自定义数据结构时,迭代器是自定义点。不幸的是,编写自己的迭代器需要相当多的样板文件。我认为 boost 可以提供帮助,但如果您想继续使用标准库提供的内容,据我所知,没有办法自己编写。
以下内容需持保留意见。我假设所有内部向量的大小都相同。我没有考虑 const_iterators
,因为你不需要它们来使用 std::stable_partition
. I have omitted some member functions that you will have to add yourself. The algorithm requires the iterator to adhere to two named concepts, namely LegacyBidirectionalIterator
and ValueSwappable
。话虽这么说,这里是如何实现一个迭代器,使您能够迭代 2d 向量的列:
#include <iostream>
#include <vector>
struct vector2d_col_iterator {
using container_t = std::vector<std::vector<int>>;
container_t& container;
size_t row;
size_t col;
vector2d_col_iterator& operator++(){
++row;
return *this;
}
bool operator==(const vector2d_col_iterator& other) const {
return col == other.col && row == other.row;
}
bool operator !=(const vector2d_col_iterator& other) const {
return !(*this == other);
}
int& operator*() { return container[row][col]; }
static vector2d_col_iterator begin(container_t& container,int col) {
return {container,0,col};
}
static vector2d_col_iterator end(container_t& container,int col) {
return {container,container.size(),col};
}
};
int main() {
std::vector<std::vector<int>> v{ {1,2,3},{4,5,6}};
auto begin = vector2d_col_iterator::begin(v,1);
auto end = vector2d_col_iterator::end(v,1);
for ( ; begin != end; ++begin) std::cout << *begin << " ";
}
输出:
2 5
Efficiency is not a really big issue, the matrices will be relatively small. I just want to find the simplest, clearest way of doing this. Preferably without having to write a stable_partition implementation from scratch.
如果矩阵真的很小(比如 ~20x20 个元素)并且效率真的不是问题,那么最简单的方法可能是仅对内部向量使用 std::stable_partition
。您可以转置矩阵,在所有内部向量的循环中调用算法,再次转置。完毕。那基本上是 ~10 行代码。您的选择 ;)
使用 range-v3,您可能会:
const std::vector<std::vector<int>> v = /*..*/;
auto is_zero = [](int e){ return e == 0; };
auto right = v;
for (auto& row : right) {
ranges::stable_partition(row | ranges::view::reverse, is_zero);
}
print(right);
auto top = v;
for (std::size_t i = 0; i != v[0].size(); ++i) {
auto col_view = top | ranges::view::transform([i](auto& row)-> int& { return row[i]; });
ranges::stable_partition(col_view, is_zero);
}
print(top);
假设您有一个二维向量定义如下:
std::vector<vector<int>> v
其中代表一个矩阵:
1 1 0 1 3
0 4 6 0 1
5 0 0 3 0
6 3 0 2 5
我想稳定分区(比如使用谓词 el != 0)这个矩阵,但是在所有方向上。这意味着我希望能够得到:
1 1 6 1 3 0 0 0 0 0 1 1 1 3 0 0 1 1 1 3
5 4 0 3 1 1 1 0 1 3 4 6 1 0 0 0 0 4 6 1
6 3 0 2 5 5 4 0 3 1 5 3 0 0 0 0 0 0 5 3
0 0 0 0 0 6 3 6 2 5 6 3 2 5 0 0 6 3 2 5
(down) (up) (right) (left)
对于两个方向,这可以非常简单地通过迭代外部向量并划分内部向量(按顺序或反向)来完成。但是对于其他方向,我不知道如何去做同样的事情。
有没有办法使用 std::stable_partition
实现此目的?是否有另一种数据结构(支持像向量一样的索引)可以让我更容易地做到这一点?
如果我有 ti 从头开始实施,是否有标准或推荐的方法来做到这一点?
您不需要编写自己的算法实现。当您想要将现有算法用于自定义数据结构时,迭代器是自定义点。不幸的是,编写自己的迭代器需要相当多的样板文件。我认为 boost 可以提供帮助,但如果您想继续使用标准库提供的内容,据我所知,没有办法自己编写。
以下内容需持保留意见。我假设所有内部向量的大小都相同。我没有考虑 const_iterators
,因为你不需要它们来使用 std::stable_partition
. I have omitted some member functions that you will have to add yourself. The algorithm requires the iterator to adhere to two named concepts, namely LegacyBidirectionalIterator
and ValueSwappable
。话虽这么说,这里是如何实现一个迭代器,使您能够迭代 2d 向量的列:
#include <iostream>
#include <vector>
struct vector2d_col_iterator {
using container_t = std::vector<std::vector<int>>;
container_t& container;
size_t row;
size_t col;
vector2d_col_iterator& operator++(){
++row;
return *this;
}
bool operator==(const vector2d_col_iterator& other) const {
return col == other.col && row == other.row;
}
bool operator !=(const vector2d_col_iterator& other) const {
return !(*this == other);
}
int& operator*() { return container[row][col]; }
static vector2d_col_iterator begin(container_t& container,int col) {
return {container,0,col};
}
static vector2d_col_iterator end(container_t& container,int col) {
return {container,container.size(),col};
}
};
int main() {
std::vector<std::vector<int>> v{ {1,2,3},{4,5,6}};
auto begin = vector2d_col_iterator::begin(v,1);
auto end = vector2d_col_iterator::end(v,1);
for ( ; begin != end; ++begin) std::cout << *begin << " ";
}
输出:
2 5
Efficiency is not a really big issue, the matrices will be relatively small. I just want to find the simplest, clearest way of doing this. Preferably without having to write a stable_partition implementation from scratch.
如果矩阵真的很小(比如 ~20x20 个元素)并且效率真的不是问题,那么最简单的方法可能是仅对内部向量使用 std::stable_partition
。您可以转置矩阵,在所有内部向量的循环中调用算法,再次转置。完毕。那基本上是 ~10 行代码。您的选择 ;)
使用 range-v3,您可能会:
const std::vector<std::vector<int>> v = /*..*/;
auto is_zero = [](int e){ return e == 0; };
auto right = v;
for (auto& row : right) {
ranges::stable_partition(row | ranges::view::reverse, is_zero);
}
print(right);
auto top = v;
for (std::size_t i = 0; i != v[0].size(); ++i) {
auto col_view = top | ranges::view::transform([i](auto& row)-> int& { return row[i]; });
ranges::stable_partition(col_view, is_zero);
}
print(top);