Add multiple values to a vector - c++

I have a vector of ints that I want to add multiple values too but too many values to add using a lot of push_backs. Is there any method of adding multiple values at the end of a vector. Something along the lines of this:
std::vector<int> values
values += {3, 9, 2, 5, 8, etc};
I found that boost has something like this, but I would like not having to include boost.
#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
{
std::vector<int> myElements;
myElements += 1,2,3,4,5;
}
Which seems to be declared like this:
template <class V, class A, class V2>
inline list_inserter<assign_detail::call_push_back<std::vector<V,A> >, V>
operator+=( std::vector<V, A>& c, V2 v )
{
return push_back( c )( v );
}
Is there any C++/C++11 way to do this or, if not, how would it be implemented?

This should work:
std::vector<int> values;
values.insert( values.end(), { 1, 2, 3, 4 } );

Perhaps with insert:
values.insert( values.end(), {3, 9, 2, 5, 8, etc} );
Demo.

In order to present as much as possible solutions, this should work too:
for(const auto x : {11, 12, 13, 14})
v.push_back(x);
Demo.

You can just make an operator:
template <class T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::initializer_list<T> l)
{
lhs.insert(std::end(lhs), l);
return lhs;
}

You can mimic the boost boost::assign behavior
template <typename T>
class vector_adder
{
public:
std::vector<T>& v;
vector_adder(std::vector<T>& v):v(v)
{ }
vector_adder& operator,(const T& val)
{
v.push_back(val);
return *this;
}
};
template <typename T>
vector_adder<T> operator+=(std::vector<T>& v,const T& x)
{
return vector_adder<T>(v),x;
}
Then,
std::vector<int> v {1,2,3,4};
v += 11,12,13,14 ;
See here

You can do it by using the insert member function, as such:
vector<int> v;
int myarr[] {1, 2, 4, 5, 5, 6, 6, 8}; //brace initialization with c++11
v.insert(v.end(), myarr, myarr+8);
There was a previous answer that omitted the middle argument in the insert parameters, but that one does not work. There are several formats to follow for the insert method, which can be found here and the code snippet I wrote practically follows this format:
vectorName.insert(postion to start entering values, first value to enter, how many values to enter)
Note: That the last two arguments (i.e. myarr, myarr+8) use pointer arithmetics. myarr is the address in memory of the first element in the array, and the second value is the address of the 8th element. You can read about pointer arithmetic here.
Hope that helps!

Related

polymorphism between set and multiset in c++

Is there a way using polymorphism to have a generic for set and multiset? as follows.
Note: but only for sets, (set, multiset)
template<typename T>
void foo(parent_set<T> &s) {
// do something
}
// main
set<int> s1 = {1, 2, 3, 4, 5};
foo(s1);
multiset<int> s2 = {1, 2, 2, 2, 2, 3};
foo(s2);
Well, why don't you make the whole container your template parameter?
template <class SetType>
void foo( SetType& s)
{
using T = typename SetType :: value_type;
enter code here
....
}
The restriction for the parameter to only be a set or multiset, as is usually done with templates, is enforced by the usage of the template parameter as a set. E.g. you call insert with a single parameter, and therefore you cannot pass a vector. If there is a third, unknown, container that has all the required interface, maybe it makes sense to allow it as well?

Insert into vector with conditional iterator

Say I have a vector with various entries, which I want to insert into another vector, while leaving out entries that satisfy a condition.
For example, I want to insert a vector while leaving out all three's.
{1, 3, 2, 3, 4, 5, 3} -> { /* previous content, */ 1, 2, 4, 5}
What I came up with so far uses std::partition, which does not preserve the relative order and rearranges the source vector.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
auto partition = std::partition(std::begin(source),
std::end(source), [](const auto& a) { return a == 3; });
target.insert(std::begin(target), partition, std::end(source));
What I am looking for is more of an iterator that checks a condition and moves on if the condition is not satisfied. Something like this:
target.insert(std::begin(target),
conditional_begin(source, [](const auto& a) { return a != 3; }),
conditional_end(source));
I suppose a conditional_end function would be necessary, since std::end would return a different iterator type than conditional_begin.
Maybe I have overlooked something, so my questions are:
Does the standard library provide something similar?
Is there a different easy way to achieve my goal?
Is there an easy way to implement the conditional iterator functionality?
Is there a different easy way to achieve my goal?
Yes, the standard already has this functionality built in. The function you are looking for is std::copy_if.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), [](auto val){ return val != 3; });
Here, std::back_inserter(target), will call push_back on target for each element that the predicate returns true.
Yes, you can create a custom iterator that does what you want but it is currently a little tedious to create custom iterators using standard C++. It would look something like this:
template <typename Itr, typename F>
struct ConditionalIterator {
Itr itr;
Itr end;
F condition;
using value_type = typename Itr::value_type;
using difference_type = typename Itr::difference_type;
using pointer = typename Itr::pointer;
using reference = typename Itr::reference;
using iterator_category = std::forward_iterator_tag;
ConditionalIterator() = default;
ConditionalIterator(Itr itr, Itr end, F condition): itr(itr), end(end), condition(condition) {}
bool operator!=(const ConditionalIterator &other) const { return other.itr != itr; }
reference operator*() const { return *itr; }
pointer operator->() const { return &(*itr); }
ConditionalIterator& operator++() {
for (; ++itr != end;) {
if (condition(*itr))
break;
}
return *this;
}
ConditionalIterator operator++(int) {
ConditionalIterator ret(*this);
operator++();
return ret;
}
};
You can then create something like the conditional_begin and conditional_end helper functions you asked for. The only issue is that std::vector::insert expects the two iterators to have the same type. If we use a lambda for our condition then this will be part of the type of our conditional iterator. So we need to pass the lambda to both helper functions so that they return iterators with matching types:
template <typename C, typename F>
auto conditional_begin(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.begin(),
source.end(), f);
}
template <typename C, typename F>
auto conditional_end(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.end(),
source.end(), f);
}
Which you could call with a lambda like this:
auto condition = [](const auto &a) { return a != 3; };
target.insert(std::begin(target),
conditional_begin(source, std::ref(condition)),
conditional_end(source, std::ref(condition)));
Live demo.
My crude tests show, in this case, this ends up being significantly faster than simply using copy_if and back_inserter because std::vector::insert first works out how much memory to allocate before inserting. Just using back_inserter will cause multiple memory allocations. The difference in performance will depend on how expensive the condition is to evaluate. You can get the same speedup by using count_if to reserve enough space before using copy_if:
auto count = static_cast<size_t>(std::count_if(source.begin(),
source.end(), condition));
target.reserve(target.size() + count);
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), condition);
Live demo.
As ranges will be standardized soon, this is an alternative using range-v3, the reference library for the proprosal:
#include <range/v3/view/concat.hpp>
#include <range/v3/view/filter.hpp>
using namespace ranges;
const std::vector<int> source{1, 3, 2, 3, 4, 5, 3};
const std::vector<int> target = view::concat(source,
source | view::filter([](auto i){ return i != 3; }));

How to compare a container and a initializer-list to see if they are equal?

For example
template<class Container, class List>
bool isEqual(Container const& c, List const& l)
{
return c == Container(l); // Error!!
}
And check by
std::vector<int> v;
bool b = isEqual(v, {1, 2, 3});
But error in my code. No conversion from list to container. How to fix the bug?
Your example, as currently written, will not only fail to compile because of the comparison, but also because the template parameter List cannot be deduced from a braced-init-list.
Either change the function to
template<class Container, class T>
bool isEqual(Container const& c, std::initializer_list<T> const& l)
or change the way you call it
std::vector<int> v;
auto l = {1, 2, 3};
bool b = isEqual(v, l);
// or
bool b = isEqual(v, std::initializer_list<int>{1, 2, 3});
To fix the comparison, as Igor mentions in the comments, use
return c.size() == l.size() && std::equal(std::begin(c), std::end(c), std::begin(l));
Or, if you have access to the C++14 overload of std::equal that takes begin and end iterators to both ranges, you can skip the size check
return std::equal(std::begin(c), std::end(c), std::begin(l), std::end(l));

Converting from int[] to list<int> : Any better way

I have an integer array as shown:
int ia[] = {1, 2, 3, 4, 5, 6};
I want to convert it to a list<int> and a vector<int>. The obvious way that comes to my mind is iterating over the array, and add the elements to the list<int> and vector<int>:
for (auto val: ia) {
ilist.push_back(val);
ivec.push_vack(val);
}
I just wanted to know, whether there is any other way, probably any available library function?
You can use a two-iterator constructor:
std::list<int> ilist(std::begin(ia), std::end(ia));
std::vector<int> ivec(std::begin(ia), std::end(ia));
If you don't have C++11 support for std::begin and std::end, you can use
std::list<int> ilist(ia, ia + 6);
where in real code you would aim to provide an array length function instead of using 6 explicitly.
Better still, you could role out your own begin and end function templates, for example
template< class T, std::size_t N >
T* my_end( const T (&a)[N] )
{
return &a[N];
}
Edit here's an array length function template:
template< class T, size_t N >
std::size_t size( const T (&)[N] )
{
return N;
}

+= on a vector without boost

Is there any way to use the += operator with a vector without using boost or using a derivated class?
Eg.
somevector += 1, 2, 3, 4, 5, 6, 7;
would actually be
somevector.push_back(1);
somevector.push_back(2);
somevector.push_back(3);
etc.
With a little ugly operator overloading, this isn't too difficult to accomplish. This solution could easily be made more generic, but it should serve as an adequate example.
#include <vector>
Your desired syntax uses two operators: the += operator and the , operator. First, we need to create a wrapper class that allows us to apply the , operator to push an element onto the back of a vector:
template <typename T>
struct push_back_wrapper
{
explicit push_back_wrapper(std::vector<T>& v) : v_(&v) { }
push_back_wrapper& operator,(const T& x)
{
v_->push_back(x);
return *this;
}
std::vector<T>* v_;
};
Then, in order to use this in conjunction with += on a vector, we overload the += operator for a vector. We return a push_back_wrapper instance so that we can chain push backs with the comma operator:
template <typename T, typename U>
push_back_wrapper<T> operator+=(std::vector<T>& v, const U& x)
{
v.push_back(x);
return push_back_wrapper<T>(v);
}
Now we can write the code you have in your example:
int main()
{
std::vector<int> v;
v += 1, 2, 3, 4, 5, 6, 7;
}
The v += 1 will call our operator+= overload, which will return an instance of the push_back_wrapper. The comma operator is then applied for each of the subsequent elements in the "list."
Not with syntax like that, no. But you could do something like this:
int tmparray[] = {1, 2, 3, 4, 5, 6, 7};
somevector.insert(somevector.end(),
tmparray,
tmparray + (sizeof(tmparray) / sizeof(tmparray[0])));