I guess this is a simple question. I need to do something like this:
std::set<int> s1, s2;
s1 = getAnExcitingSet();
std::transform(s1.begin(), s1.end(), std::back_inserter(s2), ExcitingUnaryFunctor());
Of course, std::back_inserter doesn't work since there's no push_back.
std::inserter also needs an iterator? I haven't used std::inserter so I'm not sure what to do.
Does anyone have an idea?
Of course, my other option is to use a vector for s2, and then just sort it later. Maybe that's better?
set doesn't have push_back because the position of an element is determined by the comparator of the set. Use std::inserter and pass it .begin():
std::set<int> s1, s2;
s1 = getAnExcitingSet();
transform(s1.begin(), s1.end(),
std::inserter(s2, s2.begin()), ExcitingUnaryFunctor());
The insert iterator will then call s2.insert(s2.begin(), x) where x is the value passed to the iterator when written to it. The set uses the iterator as a hint where to insert. You could as-well use s2.end().
In 2016 there was a proposal to have a "single argument inserter iterator".
https://isocpp.org/files/papers/p0471r0.html . I couldn't find if it the proposal advanced. I think it makes sense.
For now you can have this behavior defining the maker function:
template<class Container>
auto sinserter(Container& c){
using std::end;
return std::inserter(c, end(c));
}
Used as:
std::transform(begin(my_vec), end(my_vec), sinserter(my_set), [](auto& e){return e.member;});
Related
I have a std::vector<boost::optional<double>>, foo say. In this particular instance I need a std::vector<double> where any "optional" element in the other vector maps to a 0 in the new one.
Am I missing a one-line solution for this?
The other choice is the unsatisfactory
std::vector<double> out(foo.size());
for (auto& it : foo){
out.push_back(it ? *it : 0.0);
}
I'd welcome a solution based on std::optional, even though I don't use that standard yet.
std::transform solution:
std::vector<double> out(foo.size());
std::transform(foo.begin(), foo.end(), out.begin(), [](const auto& opt){ return opt.value_or(0.0); });
Edit: Added the out definition.
Here's a solution that constructs the output vector with the desired values. Still can't be forced onto one line though.
auto valueOrZero = [](auto opt){ return opt?*opt:0.0; };
std::vector<double> out(boost::make_transform_iterator(std::begin(foo), valueOrZero), boost::make_transform_iterator(std::end(foo), valueOrZero));
Unfortunately, boost::transform_iterator requires the unary transformation function to be specified for the end iterator, and you can't just repeat the lamdba definition because it also requires both iterators to have exactly the same type. This forces the lambda onto its own line.
I think it would be possible to write a transform iterator that works around this, but you'd have to do it from scratch.
I have the following object
std::vector<std::vector<std::string>> vectorList;
Then I add to this using
std::vector<std::string> vec_tmp;
vec_tmp.push_back(strDRG);
vec_tmp.push_back(strLab);
if (std::find(vectorList.begin(), vectorList.end(), vec_tmp) == vectorList.end())
vectorList.push_back(vec_tmp);
The std::vector<std::string>s contained vectorList are only ever 2-dimensional and there are no duplicates. This works great, but I now only want to check if vectorList contains an item that index zero equal to the current strDrg. In C# I would not even be thinking about this, but this does not seem straight forward using C++. How can I find if a vector exists in vectorList where strDrg already exists in vectorList.at(i)[0]?
Note: I can use boost.
Use find_if with a lambda:
std::find_if(vectorList.begin(), vectorList.end(),
[&strDrg](const std::vector<std::string>& v) { return v[0] == strDrg; });
It seems you don't need the full power of vector for you inner elements. Consider using:
std::vector<std::array<std::string, 2>>
instead.
For doing exactly what you asked, std::find_if with a lambda as #chris proposed in comments is the best:
std::find_if(ob.begin(), ob.end(),
[&](const auto x){return x[0] == strDRG;});
// Replace auto with "decltype(ob[0])&" until
//you have a C++1y compiler. Might need some years.
But if you only ever have exactly two elements, consider using a std::array<...>, a std::pair<...> or a std::tuple<...> instead of the inner vector.
For tuple and pair, you need to access the first element differently:
pair : member first
tuple: use get<0>(x);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Delete Duplicate Entries in a vector
I need to delete double entries in C++ STL vectors. An important point is that the order of elements in the resulting vector must be equivalent to the order in the input vector. Is there an algorithm (e.g. in stl, boost) which would do this?
There are two possible cases here: either the vector is already sorted or it isn't.
If it is, std::erase and std::unique can easily solve this as shown in the other answers.
If it isn't then you can do achieve the goal with
v.erase(std::remove_if(v.begin(), v.end(), predicate), v.end());
but there's a problem in that predicate is not trivial to specify: it's a function that accepts one argument (the value to consider) and it needs to answer the question "is there any equal value earlier in the vector?". Since you aren't told where exactly in the vector the supplied argument is, that means you 'd have to keep quite a bit of manual state to be able to answer this.
A convenient option here would be to use an std::set to do some of the heavy lifting:
std::set<decltype(v)::value_type> set(v.begin(), v.end());
v.erase(
std::remove_if(
v.begin(),
v.end(),
[&set] (decltype(v)::value_type item) { return !set.erase(item); }),
v.end());
What this does is prepopulate an std::set with the values in the vector and then check if an item has been seen before by seeing if it has been removed from the set. This way the result will retain only the first item from each set of items that compare equal in the input.
See it in action.
If your vector is not sorted and you thus cannot just use std::unique (and likewise cannot sort it which would destroy your order), you can use something like this function (using C++11 lambdas):
template<typename FwdIt> FwdIt unordered_unique(FwdIt first, FwdIt last)
{
typedef typename std::iterator_traits<FwdIt>::value_type value_type;
std::set<value_type> unique;
return std::remove_if(first, last, [&unique](const value_type &arg) {
return !unique.insert(arg).second; });
}
Which can be invoke using the usual erase-romve-idiom:
v.erase(unordered_unique(v.begin(), v.end()), v.end());
Of course you can also use C++11's std::unordered_set instead of a std::set (for hashable types, of course) to get away from O(n log n) in average case.
How about std::unique?
auto firstDup = std::unique(myvector.begin(), myvector.end());
Use next:
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
I was thinking about using remove_if on a vector of strings as follows in the pseudo code below:
for(some strings in a given set) {
remove_if(myvec.begin(), myvec.end(), string_matches_current_string);
}
Now, I am aware I can define the predicate and make this work easily. But I was wondering if there is a standard template function that I could use in place of the predicate above to make this work. I was looking around and couldn't find one. Appreciate any ideas with examples. Thanks!
Why using std::remove_if if you already know the value you want to remove? Use std::remove, which removes the items in the provided range, that match the given value:
std::vector<std::string>::iterator new_end = my_vec.end();
for(const auto ¤t_set_string : some_set)
new_end = std::remove(myvec.begin(), new_end, current_set_string);
my_vec.erase(new_end, my_vec.end()); // effectively remove them from the vector.
Note that I used the range-based for loop just to make this shorter, but you should use a regular loop if you can't use C++11.
I'm pretty sure there isn't a standard function but you can easily write the whole expression using a C++11 lambda:
std::remove_if(myvec.begin(), myvec.end(),
[&compare_me](std::string const& cmp) -> bool
{
return compare_me == cmp;
});
With compare_me being the "current" string set by the outer loop.
Keep in mind that remove_if returns an iterator to one past the last valid element so in order to get the correct myvec, you have to erase the elements between the iterator returned by remove_if and myvec.end().
For a non-C++11 implementation you'd have to turn the lambda into a function or functor. If you turn it into a functor you can pass the functor directly, if you turn it into a function you'll have to use something like boost::bind to provide the necessary glue.
Short of (the obvious) building a C style string first then using that to create a std::string, is there a quicker/alternative/"better" way to initialize a string from a vector of chars?
Well, the best way is to use the following constructor:
template<class InputIterator> string (InputIterator begin, InputIterator end);
which would lead to something like:
std::vector<char> v;
std::string str(v.begin(), v.end());
I think you can just do
std::string s( MyVector.begin(), MyVector.end() );
where MyVector is your std::vector.
With C++11, you can do std::string(v.data()) or, if your vector does not contain a '\0' at the end, std::string(v.data(), v.size()).
std::string s(v.begin(), v.end());
Where v is pretty much anything iterable. (Specifically begin() and end() must return InputIterators.)
I like Stefan’s answer (Sep 11 ’13) but would like to make it a bit stronger:
If the vector ends with a null terminator, you should not use (v.begin(), v.end()): you should use v.data() (or &v[0] for those prior to C++17).
If v does not have a null terminator, you should use (v.begin(), v.end()).
If you use begin() and end() and the vector does have a terminating zero, you’ll end up with a string "abc\0" for example, that is of length 4, but should really be only "abc".
Just for completeness, another way is std::string(&v[0]) (although you need to ensure your string is null-terminated and std::string(v.data()) is generally to be preferred.
The difference is that you can use the former technique to pass the vector to functions that want to modify the buffer, which you cannot do with .data().
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());