Using front_inserter instead of back_inserter - c++

guys!
I'm trying to understand the work of iterators, so in the code below,is it possible to change back_inserter to front_inserter without changing underlying data (structure).
Could you,please,explain why. If change is possible consider its key idea.
int a1[] = { 0, 1, 2, 3, 4, 5, 6 };
int a2[] = { 1, 4, 5 };
std::vector<int> a3;
int a4[] = { 0, 2, 3, 6 };
std::set_difference(a1, a1 + 7, a2, a2 + 3, std::back_inserter(a3));
assert(std::equal(a3.begin(), a3.end(), a4));
Thank you all!

An insert iterator is simply an implementation of an iterator which inserts something in to a collection using standard mechanisms. In the case of back_inserter, the insertion is done by calling the push_back() method on the container. Hence, in order to use back_inserter, the container must implement push_back().
Likewise, with front_inserter the collection mush implement push_front(), which vector does not. Therefore, you can't use front_inserter on a vector.
list and deque both implement push_front, so if you were to use one of those rather than a vector, you could use front_inserter.

No, but what you want is an inserter:
std::set_difference(a1, a1 + 7, a2, a2 + 3, std::inserter(a3, a3.begin()));

Related

How to insert std::vector or array to a std::forward_list without using any loop?

forward_list<int> listOne;
forward_list<int> listTwo;
vector<int> arr = {2,4,3};
forward_list<int>::iterator it;
In the code mention above, I want to insert a std::vector in listOne and I tried using insert_after function.
it = listOne.begin();
listOne.insert_after(it,arr);
But it didn't work.
I want to know that, is there a way to add a std::vector or array in a std::forward_list without any loop ?
I want to know that, is there a way to add a std::vector or std::array in a std::forward_list without any loop?
Since the question is more generic, I would like to give all the possible solutions using std::forward_list itself:
Using the range constructor of the std::forward_list5
std::vector<int> arr{ 1, 2, 4, 3 };
std::forward_list<int> listOne{ arr.cbegin(), arr.cend() };
Using the assignment std::forward_list::operator=3 (creates a temp std::initializer_list from range passed)!
std::vector<int> arr{ 1, 2, 4, 3 };
std::forward_list<int> listOne = { arr.cbegin(), arr.cend() };
To replaces the contents of the forward_list, via member std::forward_list::assign()
std::vector<int> arr{ 1, 2, 4, 3 };
std::forward_list <int> listOne{ 11, 22 };
listOne.assign(arr.cbegin(), arr.cend()); // replaces the { 11, 22 }
To inserts elements after the specified position in the forward list via the member std::forward_list::insert_after()
std::vector<int> arr{ 1, 2, 4, 3 };
std::forward_list <int> listOne{ 0 };
// insert the arr after the first element
listOne.insert_after(listOne.begin(), arr.cbegin(), arr.cend());
Here is a demo of above all.
You could use a std::copy with std::front_inserter
copy(arr.rbegin(), arr.rend(), front_inserter(listOne));
Working demo
If you need it on construction you can pass begin() and end() iterators to the forward_list constructor:
std::vector<int> vec{1, 2, 3, 4, 5, 6};
std::forward_list<int> list{vec.cbegin(), vec.cend()};

Add element to function in place C++

Add element to function in place C++
Python code:
l1 = [1, 2, 3]
l2 = l1 + [4]
print(l2) #[1, 2, 3, 4]
l3 = l1+l2
print(l3) #[1, 2, 3, 1, 2, 3, 4]
Is there a way to do this in C++
You clarified in a comment that you want to do it "in place". In C++17 there isn't an operator or function in the standard library for concatenating two vectors (or containers), but it is pretty easy to create one yourself:
template <class T>
std::vector<T> concat(const std::vector<T>& v1, const std::vector<T>& v2)
{
auto res = v1;
res.insert(res.end(), v2.begin(), v2.end());
return res;
}
In C++20 all this changes as we will get ranges.
Until then you can use the ranges-v3 library (on which the standard ranges are based):
views::concat(v1, v2);
This returns a range. That should be enough as you should take range views as parameters or at least iterators. The advantage is that views are lazy. They don't do the actual transformations until you iterate over them and don't create new containers. If you however still need a vector you can do that like this:
#include <range/v3/view.hpp>
using namespace ranges;
auto test()
{
std::vector v1{10, 20, 30};
std::vector v2{1, 2, 3, 4, 5};
auto v = views::concat(v1, v2) | to<std::vector>();
}
There has been a comment about creating an overloaded operator+ instead of the function. That would be a bad idea for a few reasons:
Overloading an operator with only standard classes as parameters is a bad idea as you can't open namespace std to define it there and defining it elsewhere will cause problems with ADL.
Second, even if you could, a golden rule is to overload an operator to do expected things. In this case, an operator+ would be expected by (some/most) people to do element-wise addition.
I believe you're trying to add an element to a vector in c++.
vector<int> v; // { }
v.push_back(10); // { 10 }
To append one vector to another vector, you could use insert
vector<int> v = { 11, 12 };
vector<int> v2 = { 13, 14 };
v.insert(v.end(), v2.begin(), v2.end()); // { 11, 12, 13, 14 }
The first parameter to insert is an iterator pointing to where you want the second vector's elements to be inserted. The 2nd and 3rd parameters are the iterators pointing to the beginning and end of the second vector, they denote the boundaries of which elements to insert into the first vector.
This operation effectively appends the second vector into the first vector.

Pass in an iterator that iterates only elements satisfying certain conditions

In C++, is it possible to pass in an iterator that iterates only elements satisfying certain conditions? While it is certainly possible to write my own iterator class, I'm wondering there exists a standard library solution. For example, the constructor of std::discrete_distribution takes an input of two iterators (begin and end). Now I would need to do the following:
std::vector<int> x = {1, 2, 3, 4, 5};
std::vector<int> y;
std::copy_if(x.begin(), x.end(), std::back_inserter(y), my_condition);
std::discrete_distribution dd(y.begin(), y.end());
But this would require to copy the elemnts of y twice. I would prefer something like following:
std::vector<int> x = {1, 2, 3, 4, 5};
std::discrete_distribution dd(std::condition_iter(x.begin(), my_condition), x.end());
There is neither special syntax nor standard library feature in C++ which could solve your problem. However, there is a library called "range-v3" that might help. Here are a couple of links:https://github.com/ericniebler/range-v3https://ericniebler.github.io/range-v3/Look for view::remove_if - I think this is what you need. This will filter the container on the fly without actually modifying anything.

How can I pass a part of a vector as a function argument?

I'm using a vector in a C++ program and I need to pass a part of that vector to a function.
If it was C, I would need to do the following (with arrays):
int arr[5] = {1, 2, 3, 4, 5};
func(arr+2); // Pass the part of the array {3, 4, 5}
Is there any other way than creating a new vector with the last part?
A common approach is to pass iterator ranges. This will work with all types of ranges, including those belonging to standard library containers and plain arrays:
template <typename Iterator>
void func(Iterator start, Iterator end)
{
for (Iterator it = start; it !=end; ++it)
{
// do something
}
}
then
std::vector<int> v = ...;
func(v.begin()+2, v.end());
int arr[5] = {1, 2, 3, 4, 5};
func(arr+2, arr+5);
Note: Although the function works for all kinds of ranges, not all iterator types support the increment via operator+ used in v.begin()+2. For alternatives, have a look at std::advance and std::next.
Generically you could send iterators.
static const int n[] = {1,2,3,4,5};
vector <int> vec;
copy (n, n + (sizeof (n) / sizeof (n[0])), back_inserter (vec));
vector <int>::iterator itStart = vec.begin();
++itStart; // points to `2`
vector <int>::iterator itEnd = itStart;
advance (itEnd,2); // points to 4
func (itStart, itEnd);
This will work with more than just vectors. However, since a vector has guaranteed contigious storage, so long as the vector doesn't reallocate you can send the addresses of elements:
func (&vec[1], &vec[3]);
The latest (C++20) approach is to use std::span. Create a std::span that views a part of std::vector and pass it to functions. Note: the elements must be continuous in memory to use std::span on a container, and std::vector is continuous in memory.
#include <span>
std::vector<int> int_vector = {1, 2, 3, 4, 5};
std::span<int> a_span(int_vector.data() + 2, int_vector.size() - 2);
for(const int a : a_span);
for(const int& a : a_span);
function(a_span);
As of C++20, I would make use of a range from the Ranges library, because it offers a variety of range adaptors for creating different views on you vector. For your use case, I would use the range adaptor std::views::drop as follows:
int main() {
std::vector<int> arr {1, 2, 3, 4, 5};
// Ignore the first two elements and pass only {3, 4, 5} to func().
func(arr | std::views::drop(2));
return 0;
}
This way you don't have to bother with interators or pointer/iterator arithmetic.
Also, no temporary vector is created for your shortened arr, because the view adaptor drop() creates a range that doesn't contain elements. The resulting range is just a view over the original vector arr, but with a customized iteration behavior.
For the declaration of func() I would use the placeholder type auto for the function parameter, because the type of the resulting range is quite complex. This makes func() a function template, though:
void func(auto range) {
for (int i : range)
std::cout << i << std::endl;
}
(Alternatively, you could pass arr by reference to func() and apply the range adaptor inside func().)
Output:
3
4
5
Code on Wandbox
std::vector<char> b(100);
send(z,&b[0],b.size(),0);
Try out this.
Read this too.
As some others already stated you can use iterators for that. You'll have to pass the start of the sequence and the end of the sequence to your worker function.
If you need more flexibility, you should take a look at slice. With slice you can for example retrieve every n-th entry of the vector.
I was also stuck to same problem.I found one really nice trick.Suppose you want to find the minimum in range L to R (both inclusive) of arr then you can do something like this:
vector<int>arr = {4,5,1,3,7};
int minVal = *min_element(begin(arr)+L,begin(arr)+(R+1));
Means you pass the complete array and range and then you can apply the above trick.

stl insertion iterators

Maybe I am missing something completely obvious, but I can't figure out why one would use back_inserter/front_inserter/inserter,
instead of just providing the appropriate iterator from the container interface.
And thats my question.
Because those call push_back, push_front, and insert which the container's "normal" iterators can't (or, at least, don't).
Example:
int main() {
using namespace std;
vector<int> a (3, 42), b;
copy(a.begin(), a.end(), back_inserter(b));
copy(b.rbegin(), b.rend(), ostream_iterator<int>(cout, ", "));
return 0;
}
The main reason is that regular iterators iterate over existing elements in the container, while the *inserter family of iterators actually inserts new elements in the container.
std::vector<int> v(3); // { 0, 0, 0 }
int array[] = { 1, 2, 3 };
std::copy( array, array+3, std::back_inserter(v) ); // adds 3 elements
// v = { 0, 0, 0, 1, 2, 3 }
std::copy( array, array+3, v.begin() ); // overwrites 3 elements
// v = { 1, 2, 3, 1, 2, 3 }
int array2[] = { 4, 5, 6 };
std::copy( array2, array2+3, std::inserter(v, v.begin()) );
// v = { 4, 5, 6, 1, 2, 3, 1, 2, 3 }
The iterator points to an element, and doesn't in general know what container it's attached to. (Iterators were based on pointers, and you can't tell from a pointer what data structure it's associated with.)
Adding an element to an STL container changes the description of the container. For example, STL containers have a .size() function, which has to change. Since some metadata has to change, whatever inserts the new element has to know what container it's adding to.
It is all a matter of what you really need. Both kinds of iterators can be used, depending on your intent.
When you use an "ordinary" iterator, it does not create new elements in the container. It simply writes the data into the existing consecutive elements of the container, one after another. It overwrites any data that is already in the container. And if it is allowed to reach the end of the sequence, any further writes make it "fall off the end" and cause undefined behavior. I.e. it crashes.
Inserter iterators, on the other hand, create a new element and insert it at the current position (front, back, somewhere in the middle) every time something is written through them. They never overwrite existing elements, they add new ones.