使用 stl 置换 std::vector 元素的最短解决方案
Shortest solution to permute the elements of a std::vector using stl
假设您有某种类型 T
的 std::vector<T>
和该向量的索引选择 std::vector<int>
。现在我正在寻找一个函数 permute(const std::vector<T>& vector, const std::vector<int>& indices)
,returns 相对于给定索引的置换向量。
这个问题很容易通过编写如下所示的简短函数来解决:
template<typename T>
std::vector<T> permute(const std::vector<T>& matrix, const std::vector<int>& indices) {
std::vector<T> ret;
for (auto p : indices) {
ret.push_back(matrix[p]);
}
return ret;
}
int main(int, char**) {
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
auto matrixPerm=permute(matrix, perm);
std::cout << matrixPerm[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << matrixPerm[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << matrixPerm[2][0] << " == " << matrix[0][0] << std::endl;
}
我现在想知道这个程序最优雅的版本是什么,如果我们可以使用 STL 甚至 Boost 库。例如,在 STL 中我们有 shuffle()
,但我们不能说以何种方式进行洗牌。
现在有没有人,如何缩短功能?
解决方案使用std::transform()
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
int main(int, char**) {
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
std::vector<std::vector<double>> output;
std::transform(perm.begin(), perm.end(), std::back_inserter(output), [&](int i) { return matrix[i]; });
std::cout << output[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << output[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << output[2][0] << " == " << matrix[0][0] << std::endl;
}
您可以将索引转换为迭代器,然后使用 Boost.Range 创建一个间接范围。
#include <iostream>
#include <iterator>
#include <algorithm>
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
using namespace boost::adaptors;
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
std::vector<std::vector<double>> output;
auto permutation = perm | transformed( [&matrix](int x) { return matrix.begin() + x; }) | indirected;
boost::copy(
permutation,
std::back_inserter(output));
std::cout << output[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << output[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << output[2][0] << " == " << matrix[0][0] << std::endl;
}
如果不需要真正的向量,您可以跳过复制元素而只处理范围。
范围适配器使用 Boost.Iterator 库中的置换迭代器。也可以直接用这个,但是要手动定义begin和end:
auto begin = make_permutation_iterator( matrix.begin(), perm.begin() );
auto end = make_permutation_iterator( matrix.end(), perm.end() );
std::copy(begin, end, std::back_inserter(output) );
假设您有某种类型 T
的 std::vector<T>
和该向量的索引选择 std::vector<int>
。现在我正在寻找一个函数 permute(const std::vector<T>& vector, const std::vector<int>& indices)
,returns 相对于给定索引的置换向量。
这个问题很容易通过编写如下所示的简短函数来解决:
template<typename T>
std::vector<T> permute(const std::vector<T>& matrix, const std::vector<int>& indices) {
std::vector<T> ret;
for (auto p : indices) {
ret.push_back(matrix[p]);
}
return ret;
}
int main(int, char**) {
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
auto matrixPerm=permute(matrix, perm);
std::cout << matrixPerm[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << matrixPerm[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << matrixPerm[2][0] << " == " << matrix[0][0] << std::endl;
}
我现在想知道这个程序最优雅的版本是什么,如果我们可以使用 STL 甚至 Boost 库。例如,在 STL 中我们有 shuffle()
,但我们不能说以何种方式进行洗牌。
现在有没有人,如何缩短功能?
解决方案使用std::transform()
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
int main(int, char**) {
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
std::vector<std::vector<double>> output;
std::transform(perm.begin(), perm.end(), std::back_inserter(output), [&](int i) { return matrix[i]; });
std::cout << output[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << output[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << output[2][0] << " == " << matrix[0][0] << std::endl;
}
您可以将索引转换为迭代器,然后使用 Boost.Range 创建一个间接范围。
#include <iostream>
#include <iterator>
#include <algorithm>
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
using namespace boost::adaptors;
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
std::vector<std::vector<double>> output;
auto permutation = perm | transformed( [&matrix](int x) { return matrix.begin() + x; }) | indirected;
boost::copy(
permutation,
std::back_inserter(output));
std::cout << output[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << output[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << output[2][0] << " == " << matrix[0][0] << std::endl;
}
如果不需要真正的向量,您可以跳过复制元素而只处理范围。
范围适配器使用 Boost.Iterator 库中的置换迭代器。也可以直接用这个,但是要手动定义begin和end:
auto begin = make_permutation_iterator( matrix.begin(), perm.begin() );
auto end = make_permutation_iterator( matrix.end(), perm.end() );
std::copy(begin, end, std::back_inserter(output) );