2013-06-06 12 views
11

Łączenie wzmocnienia może zostać użyte do połączenia kontenera ciągów opcjonalnie oddzielonych łańcuchem separatora, jak pokazano w tym przykładzie: A good example for boost::algorithm::joinMoże zwiększyć: algorytm :: join() concat pojemnik pływaków?

Moje umiejętności w zakresie STL są słabe. Zastanawiam się, czy istnieje jakikolwiek sposób wykorzystania tej samej funkcji dla kontenera liczb (floats, double, ints)? Wygląda na to, że powinien być jeden lub dwa liniowe, aby dostosować go do innych typów.

Istnieje również funkcja kopiowania z STL za dobry przykład znaleźć tutaj: How to print out the contents of a vector?

Ale nie podoba mi się, jak to dodaje ciąg separatora po każdym elemencie. Chciałbym po prostu użyć boost.

Odpowiedz

21

Oczywiście można łączyć boost::algorithm::join i boost::adaptors::transformed, aby przekonwertować duble na ciągi, a następnie połączyć je ze sobą.

#include <iostream> 
#include <vector> 
#include <string> 

#include <boost/algorithm/string/join.hpp> 
#include <boost/range/adaptor/transformed.hpp> 

int main() 
{ 
    using boost::adaptors::transformed; 
    using boost::algorithm::join; 

    std::vector<double> v{1.1, 2.2, 3.3, 4.4}; 

    std::cout 
     << join(v | 
       transformed(static_cast<std::string(*)(double)>(std::to_string)), 
       ", "); 
} 

wyjściowa:

1,100000, 2,200000, 3,300000, 4,400000


Można również użyć lambda uniknąć brzydkiego oddanych

join(v | transformed([](double d) { return std::to_string(d); }), ", ") 
1

Moje umiejętności w zakresie STL są słabe. Zastanawiam się, czy jest i tak, aby użyć tej samej funkcji dla kontenera liczb (floats, doubles, ints)? Wydaje się, że powinien istnieć jeden lub dwa liniowy, aby dostosować go do innych typów.

std::accumulate pozwala zrobić krotnie w stosunku do wszelkich (wejściowego) Zakres iteracyjnej, wykorzystując binarną funkcję, która może przybierać różne typy dla „akumulator” i następnego elementu. W twoim przypadku: funkcja pobierająca std::string i double (lub cokolwiek innego), która łączy podany std::string z wynikiem std::to_string na drugim parametrze.

template<typename Container> 
std::string contents_as_string(Container const & c, 
           std::string const & separator) { 
    if (c.size() == 0) return ""; 
    auto fold_operation = [&separator] (std::string const & accum, 
             auto const & item) { 
    return accum + separator + std::to_string(item);}; 
    return std::accumulate(std::next(std::begin(c)), std::end(c), 
         std::to_string(*std::begin(c)), fold_operation); 
} 

Jak widać, jest to całkowicie niezależne od typu wartości pojemnika. Tak długo, jak możesz przekazać go do std::to_string jesteś dobry. W rzeczywistości powyższy kod jest niewielką odmianą the example presented for std::accumulate.

Demo of above function:

int main() { 
    std::vector<double> v(4); 
    std::iota(std::begin(v), std::end(v), 0.1); 
    std::cout << contents_as_string(v, ", ") << std::endl; 

    std::vector<int> w(5); 
    std::iota(std::begin(w), std::end(w), 1); 
    std::cout << contents_as_string(w, " x ") << " = " 
    << std::accumulate(std::begin(w), std::end(w), 1, std::multiplies<int>{}) 
    << std::endl; 
} 

0,100000, 1,100000, 2,100000, 3,100000
1 x 2 x 3 x 4 x 5 = 120