如何将vector<pair<string, int>>中的字符串复制到vector<string>中?

5
我正在使用GCC 9.2.0和Boost 1.55。
我有两个向量:
vector< pair< string, int > > source;
vector< string > dest;

我需要将source向量转换为dest向量,使它只包含source向量中的string元素。

是否可以使用boost::push_back和适配器来实现?

boost::range::push_back( dest, source | /* adaptor ??? */ );

目前我有这个可行的代码,但是它需要进行修改:

transform( source.begin(), source.end(), back_inserter(dest), __gnu_cxx::select1st< std::pair< std::string, int > >() );

应该是范围的一个典型示例。 - SergeyA
4个回答

4
为了继续发布最小的改进,以下是内容:

在编译器浏览器上实时运行

#include <boost/range/adaptor/map.hpp>
#include <fmt/ranges.h>

using namespace std::string_literals;
using namespace boost::adaptors;

template <typename R>
auto to_vector(R const& range) {
    return std::vector(boost::begin(range), boost::end(range));
}

int main() {
    std::vector source {std::pair {"one"s,1},{"two",2},{"three",3}};

    fmt::print("keys {}\nvalues {}\n",
            source | map_keys,
            source | map_values);
    
    // if you really need the vectors
    auto keys   = to_vector(source | map_keys);
    auto values = to_vector(source | map_values);
}

打印
keys {"one", "two", "three"}
values {1, 2, 3}

完美,map_keys适配器正是我正在寻找的!!! - Hardwired

3

您可以使用带有lambda的std::transformstd::back_inserter

#include <algorithm> // transform
#include <iterator>  // back_inserter

std::transform(source.begin(), source.end(), std::back_inserter(dest),
               [](auto& p) {
                   return p.first;
               });

当然,谢谢。我只是想知道是否可能使用boost算法来“简化”这行代码。 - Hardwired
@AlexandrDerkach 我不是100%确定,但这可能是其中一个Boost算法,已经被纳入标准。 - Ted Lyngmo
1
@AlexandrDerkach,请看一下我的回答 - Enlico
1
我真的需要开始学习这些范围的东西...看起来不错。 - Ted Lyngmo
1
@TedLyngmo,C++中的函数式编程一书中有关范围的章节是免费的。 - Enlico
显示剩余2条评论

3

以下是使用range-v3库的解决方案:

auto dest = source 
          | ranges::views::keys 
          | ranges::to<std::vector<std::string>>;

这里是一个演示


在C++20中,没有std::ranges::to,但如果dest已经存在,你仍然可以复制键到dest

std::ranges::copy(source | std::views::keys, 
                  std::back_inserter(dest));

这里有一个演示

注意,这在Clang trunk上不起作用,我认为这是一个错误。


又一个不错的例子 - 这是我的C++20尝试 - 我找不到ranges::to的标准版本,我还尝试使用<format>中的fmt::print,但似乎g++clang++都没有<format>头文件。 - Ted Lyngmo
1
@TedLyngmo 不错 :) 是的,还没有人实现<format>。我本来想发布一个使用std::ranges::copy填充dest的解决方案,但是无法使其正常工作。我本来想写一个问题,但被分心了。谢谢你的评论,提醒了我 :) 顺便说一下,std::viewsstd::ranges::views的简写,所以这样可以少打几个字符。 - cigien
不用谢 :-) 我找到了为什么我找不到ranges::to: C++23 Ranges 的计划-P2214r0-视图附录: "一个关键的缺失功能是ranges::to[P1206R1]。" - Ted Lyngmo
1
@TedLyngmo 嗯,它在GCC中可以工作,但在Clang中不行。我认为这是一个Clang的bug,因此我已经更新了一个使用C++20范围的解决方案。 - cigien
1
@TedLyngmo 哦,是啊,当 to 没有进入 C++20 时,我感到相当失望 :( 但我想我们不能一次拥有所有好东西 :p - cigien

3
这是一个使用transformed适配器的优化方案:
#include <boost/range/adaptor/transformed.hpp>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

using boost::adaptors::transformed;

// define function object (so we can pass it around) emulating std::get
template<std::size_t N>
auto constexpr get = [](auto const& x){ return std::get<N>(x); };

int main()
{
    // prepare sample input
    std::vector<std::pair<std::string,int>> source{{"one",1},{"two",2},{"three",3}};

    // the line you look for
    auto dest = source | transformed(get<0>);

    // dest is a vector on which we can iterate
    for (auto const& i : dest) {
        std::cout << i << '\n';
    }

    // if you really need it to be a vector
    auto dest_vec = boost::copy_range<std::vector<std::string>>(dest);
}

2
@TedLyngmo,dest是一个视图。你可以通过boost::copy_range获取实际的向量。请看我的更改。 - Enlico
1
不错。std::vector<std::string> dest_vec(dest.begin(), dest.end()); 似乎也可以工作。你得到了我的投票 :-) - Ted Lyngmo
1
@TedLyngmo,你也收到我的了。 - Enlico
2
Boost比那个更方便!https://godbolt.org/z/o5Wh7o (/cc @TedLyngmo选择以另一个竞争者的身份发布) - sehe
1
@sehe 太棒了!我很少会给一个问题点赞,回答问题并且点赞_所有_其他的答案 :-) 你们所有人让我学到了很多。 - Ted Lyngmo
显示剩余4条评论

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