2012-12-22 30 views
3

boost::algorithm::join提供了一个方便的加入std::vector<std::string>如何在元组上使用boost :: algorithm :: join?

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

这并不难与循环,但我正在寻找一种解决方案,使使用最多的标准算法和C + + 11功能(如lambda)。

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

CODE

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

编辑

OK,我把kassak的建议之下,并在boost::transform_iterator()接过来一看 - 我被推迟由示例的详细程度提升自己的文档里,所以我尝试了std::transform() - 这不是我想要的那么短,但它似乎工作。

ANSWER

#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; 
} 
+0

您的版本的缺点是它是两个步骤:完成向量文件的副本。 – Yakk

+0

@Yakk如果你能提出一个更好的版本(在代码中)作为答案,我会+1你的帖子(这将是一个很好的做法) – kfmfe04

回答

1

如果你想使用加入,你可以在boost::transform_iterator包集合,如果需要

+0

好吧 - 我基本上采取你的解决方案(看看在OP中编辑)... – kfmfe04

+0

您可以将转换后的迭代器作为'std :: pair'传递给算法,就像在@Yakk的答案中一样。 这样会更好,你不会有内存开销,你的“引用”序列会被懒惰地评估。 – kassak

3

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

然后答案变得非常干净和高效。以你正在工作的范围,转换它而不实际调用函数,然后调用它加入。

在我的手机上,所以打字相当毛茸茸的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范围库。它已经进行了基于范围的变换。

3

这是最容易使用Boost.Rangetransformed适配器:

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

您的需求是不是一个通用的一个对于为什么不只是通过载体和循环追加字符串?

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"; 
相关问题