c++ - 使用 STL 置换 std::vector 元素的最短解决方案

标签 c++ boost stl permutation combinatorics

假设您有一个 std::vector<T>某种类型的T和一系列指数 std::vector<int>这个 vector 。现在我正在寻找一个函数 permute(const std::vector<T>& vector, const std::vector<int>& indices) ,它返回关于给定索引的置换 vector 。

这个问题很容易通过编写如下所示的简短函数来解决:

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

如果您不需要真正的 vector ,您可以跳过复制元素而只处理范围。

范围适配器使用来自 Boost.Iterator 库的置换迭代器。你也可以直接使用这个,但是你必须手动定义开始和结束:

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

关于c++ - 使用 STL 置换 std::vector 元素的最短解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49769091/

相关文章:

c++ - Visual Studio 中的 "wcs"和 "_w"和 "_mbs"前缀

c++ - C++中对数组的误解

c++ - boost 函数的Python方法

c++ - 在 Visual Studio 2015 中的 C++ STL 中出现错误

c++ - 在哪里可以找到有关 "int C::*"用法的说明?

c++ - 函数调用的麻烦

c++ - 派生类不调用整个基础构造函数

c++ - 查找一个 vector 的 max_element,其中一个成员用于决定它是否是最大值

c++ - 是否需要构建 boost.signals2 库?

c++ - 从 Boost 图中删除 100,000 多个节点