How to Implode a Vector of Strings into a String (The Elegant Way)

std::vector to string with custom delimiter

Use delimiter.c_str() as the delimiter:

copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter.c_str()));

That way, you get a const char* pointing to the string, which is what ostream_operator expects from your std::string.

Join (concatenate) vector of strings to char buffer with zero byte as delimiter/terminator

Never forget the std::vector::insert method with which your example can be simplified as follows:

std::vector<std::string> string_array = { "test", "my", "string" };
std::vector<char> buffer_temp;

for(auto& s : string_array)
buffer_temp.insert(buffer_temp.end(), s.c_str(), s.c_str() + s.size() + 1);

The std::string::c_str returns a pointer to a null-terminated character array, so you don't have to append an extra '\0' to the end of each element coming from your string_array.


Responding to comments below, you can use std::string iterators as well, and because the std::string has random-access iterator you can do the following:

for(auto& s : string_array)
buffer_temp.insert(buffer_temp.end(), s.begin(), s.end() + 1);

Convert a vector int to a string

Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.

You could use a stringstream ...

#include <sstream>
//...

std::stringstream ss;
for(size_t i = 0; i < v.size(); ++i)
{
if(i != 0)
ss << ",";
ss << v[i];
}
std::string s = ss.str();

You could also make use of std::for_each instead.

Elegant way to push all declarations with a particular pattern-match into vector?


Is there a beautiful C++ feature that allows me to type something as elegant as below?

std::vector<Fl_Button *> vector_fl_button;
vector_fl_button.push_back(button_*);

No, not built-in. However, FLTK makes it possible to build the vector dynamically. The name of the objects in the C++ code is however lost in compilation so you'll need to find some other criteria.

Fortunately, Fl_Widgets, like Fl_Button have a user_data() function that can return a void* or long (really a void* that you need to cast to a long). So, if you don't want a vector of all Fl_Buttons, you can set user_data when designing the windows. Here I've used fluid to set the user_data value on a button that I like to be included in the vector:

Sample Image

Here's a function to find all widgets of a certain type placed inside another widget (like a Fl_Window) and to apply a unary predicate on the found widgets. If the predicate returns true, it stores the pointer.

widget_funcs.hpp

#ifndef WIDGET_FUNCS_HPP
#define WIDGET_FUNCS_HPP

#include <FL/Fl_Group.H>

#include <algorithm>
#include <iterator>
#include <vector>

template <class T, class UnaryPredicate>
auto find_widgets_of_type(Fl_Widget* w, UnaryPredicate pred) {
std::vector<T*> rv;

// check if "w" is a container class (essentially a dynamic_cast):
Fl_Group* g = w->as_group();

if(g) {
// Copy all the pointers that can be dynamically casted to T*
// and that fulfills the conditions in the predicate function.
std::for_each(g->array(), std::next(g->array(), g->children()),
[&rv,&pred](Fl_Widget* child) {
auto isT = dynamic_cast<T*>(child);
if(isT && pred(isT)) rv.push_back(isT);
});
}
return rv;
}

template <class T> // use this overload if you want all Fl_Buttons
auto find_widgets_of_type(Fl_Widget* w) {
return find_widgets_of_type<T>(w, [](const T*){ return true; });
}

#endif

You can then call the above function with the widget you'd like to get Fl_Buttons from as an argument:

#include "widget_funcs.hpp"

class SomeClass {
public:
SomeClass(Fl_Widget* window) :
vector_fl_button(
find_widgets_of_type<Fl_Button>(window, [](Fl_Button* b) {
return reinterpret_cast<long>(b->user_data()) == 1;
}))
{}
// ...

private:
std::vector<Fl_Button*> vector_fl_button;
};

If you need to find buttons in grandchildren too, you could just make the function recursive.

If you already use user_data for something else, you can replace the predicate in the example above with some other property that is common for all the buttons you'd like to have in the vector.

Concatenate a vector of strings/character

Try using an empty collapse argument within the paste function:

paste(sdata, collapse = '')

Thanks to http://twitter.com/onelinetips/status/7491806343

Check if a string is among the values of a map that has vector of strings as values

So you want to know if you can find the string in any of the vectors in the cluster? Use standard algorithms any_of and find:

bool stringIsContained(const ClusterDescription &cluster, const std::string &s)
{
return std::any_of(
begin(cluster), end(cluster), [&s](ClusterDescription::const_reference item)
{
return std::find(begin(item.second), end(item.second), s) != end(item.second);
}
);
}

Using standard algorithms where possible is idiomatic C++.


To address why your original code doesn't work the way you'd want it to:

You have a break in both branches of the conditional, which means the loop body will only ever execute for the first string-vector pair in the cluster.

If you simply remove the breaks, it will execute once for each string-vector pair in the cluster. Since each of the branches has an output statement, you will get one for each such pair.

If your intention is to search the whole data structure and only output at the end, you have to store the result of the search somewhere and only do output outside the loop. Which is pretty much what my code above does, except the loops are hidden in the algorithms. The result is "stored" in the return values, and you can simply act once on the final return value of the function.



Related Topics



Leave a reply



Submit