如何在元组上使用boost::algorithm::join

how to use boost::algorithm::join on tuples?

本文关键字:boost algorithm join 元组      更新时间:2023-10-16

boost::algorithm::joinstd::vector<std::string>上提供了一个方便的连接

在执行连接之前,如何扩展此功能以使用std::vector<std::tuple<std::string,bool>>将结果用单引号(用于字符串)包围(如果为true)。

这并不难做循环,但我正在寻找一个解决方案,使标准算法和c++ 11功能的最大利用(如lambdas)。

继续使用boost的join,如果可行的话:优雅/可读性/简洁更重要。

#include <string>
#include <vector>
#include <tuple>
#include <boost/algorithm/string/join.hpp> 
int main( int argc, char* argv[] )
{
  std::vector<std::string> fields = { "foo", "bar", "baz" };
  auto simple_case = boost::algorithm::join( fields, "|" );
  // TODO join surrounded by single-quotes if std::get<1>()==true
  std::vector<std::tuple< std::string, bool >> tuples =
   { { "42", false }, { "foo", true }, { "3.14159", false } };
  // 42|'foo'|3.14159 is our goal
}

编辑

好吧,我接受了kassak的建议,看看boost::transform_iterator() -我被boost自己的文档中冗长的例子所推迟,所以我尝试了std::transform() -它没有我想要的那么短,但它似乎有效。

#include <string>
#include <vector>
#include <tuple>
#include <iostream>
#include <algorithm>
#include <boost/algorithm/string/join.hpp> 
static std::string
quoted_join( 
    const std::vector<std::tuple< std::string, bool >>& tuples, 
    const std::string& join
)
{
    std::vector< std::string >  quoted;
    quoted.resize( tuples.size() );
    std::transform( tuples.begin(), tuples.end(), quoted.begin(),
        []( std::tuple< std::string, bool > const& t ) 
        {
            return std::get<1>( t ) ? 
                "'" + std::get<0>(t) + "'" :
                std::get<0>(t);
        }
    );
  return boost::algorithm::join( quoted, join );
}
int main( int argc, char* argv[] )
{
  std::vector<std::tuple< std::string, bool >> tuples =
  { 
    std::make_tuple( "42", false ), 
    std::make_tuple( "foo", true ), 
    std::make_tuple( "3.14159", false ) 
  };
  std::cerr << quoted_join( tuples, "|" ) << std::endl;
}

先写make_transform_range( old_range, functor )。对于第一个版本,假设old_range是迭代器的std::pair,但理想情况下,它应该是承认begin(c)的任何东西。

然后答案变得非常干净和高效。获取您正在处理的范围,在不实际调用函数的情况下对其进行转换,然后对其调用join。

在我的手机上,所以键入相当复杂的make_transform_range超出了我的能力。而且它很毛茸茸的。

这是一个不那么抽象的尝试。

auto functor = []( my_pair const&p )->std::string {
  if (p.second) return quote( p.first );
  return p.first;
};
auto tbegin = boost::make_transform_iterator( b, functor );
auto tend = boost::make_transform_iterator( e, functor );
join(…);

…如果有效的话,这没有我担心的那么糟糕。我仍然认为make_transform_range是值得的,但也许不是一次性的。

另一种方法是boost range库,具有所有时髦的语法。

使用Boost是最简单的。Range的transformed适配器:

#include <string>
#include <vector>
#include <tuple>
#include <iostream>
#include <algorithm>
#include <boost/algorithm/string/join.hpp> 
#include <boost/range/adaptor/transformed.hpp>
int main()
{
    std::vector<std::tuple< std::string, bool >> tuples =
    { 
        std::make_tuple( "42", false ), 
        std::make_tuple( "foo", true ), 
        std::make_tuple( "3.14159", false ) 
    };
  std::cout
      << boost::algorithm::join( 
                tuples | boost::adaptors::transformed(
                    [](std::tuple< std::string, bool > const &tup){
                        return std::get<1>(tup) ? 
                            "'" + std::get<0>(tup) + "'" :
                                  std::get<0>(tup);
                    }
                ), "|" )
      << std::endl;
}

如果您想使用join,您可以在boost::transform_iterator中包装集合并在需要时添加引号

您的要求不是通用的,为什么不只是循环遍历vector并附加字符串呢?

std::vector<std::tuple<std::string, bool>> coll;
coll.push_back(make_tuple("foo", false));
coll.push_back(make_tuple("bar", true));
coll.push_back(make_tuple("foo", false));
std::string result;
result.reserve(coll.size());
for(auto& val : coll)
{
  result += std::get<1>(val) ? ("'" + std::get<0>(val) + "'|") 
                             : std::get<0>(val) + "|";
}
boost::trim_if(result, boost::is_any_of("|"));
std::cout << result << "n";