How to copy a vector except one specific element? - c++

I have a vector with some values. How can I copy it to another vector, so all the values but a specific one (located at position x - x will be a parameter of course) would be copied?
Moreover, I would like to use the value from location x for something else, so I prefer it will be saved.
Is there an easy way to do it?

How to copy stl vector except one specific value?
You can use std::copy_if:
std::vector<T> v = ....;
std::vector<T> out;
T x = someValue;
std::copy_if(v.begin(), v.end(), std::back_inserter(out),
[x](const T& t) { return t != x; });
If you don't have C++11 support, you can use std::remove_copy_if and adjust the predicate's logic accordingly.

use std::copy_if if you have c++11, otherwise:
void foo(int n) {
std::vector<int> in;
std::vector<int> out;
std::copy(in.begin(), in.begin() + n, out.end());
std::copy(in.begin() + n + 1, in.end(), out.end());
}
This works because std::vector has random-access iterators.

As Luchian suggests, you should use erase()
#include <vector>
#include <iostream>
#include<algorithm>
int main(){
std::vector<int> vec1;
vec1.push_back(3);
vec1.push_back(4); // X in your question
vec1.push_back(5);
std::vector<int> new_vec;
new_vec = vec1;
new_vec.erase(std::find(new_vec.begin(),new_vec.end(),4));
for (unsigned int i(0); i < new_vec.size(); ++i)
std::cout << new_vec[i] << std::endl;
return 0;
}
and for your second question, to determine the index of an element in a vector
// determine the index of 4 ( in your case X)
std::vector<int>::iterator it;
it = find(vec1.begin(), vec1.end(), 4);
std::cout << "position of 4: " << distance(vec1.begin(),it) << std::endl;

Related

Cannot predetermine values for a vector

I'm using sublime text for C++ and, for some reason, I am not able to predetermine values for a vector.
std::vector<int> v = {1,2,3,4,5};
Whenever I do such a thing, I get this error:
'std::vector<int>' cannot be initialized with an initializer list
std::vector<int> v = {1,2,3,4,5};
^ ~~~~~~~~~~~
Maybe try this : std::vector v{1,2,3,4,5}; ?
Maybe try this, please
#include <iostream> // std::cout
#include <numeric> // std::iota
#include <vector> // std::vector
// Driver code
int main()
{
std::vector<int> v(6);
std::iota(v.begin(), v.end(), 1);
std::cout << "Elements are :";
for (auto i : v)
std::cout << ' ' << i;
std::cout << '\n';
return 0;
}
Output:
Elements are : 1 2 3 4 5 6
This directly answers your question:
std::vector<int> v;
for(int i=0; i<6; i++)
{
v.push_back(i);
}
To be more generic, checkout:
int myints[] = {16,2,77,29};
std::vector<int> v (myints, myints + sizeof(myints) / sizeof(int) );
Finally print the results with an iterator:
std::vector<int>::iterator vi;
for(vi = v.begin(); vi != v.end(); ++vi)
std::cout << *vi;
One more option would be to push_back() every different value you want.

initializing a vector with a lambda being fed the index in c++

Is there a library function for initializing a vector based on the index of its elements ?
This would shorten things like :
#include <vector>
using namespace std;
int main() {
auto square = [] (int n) {return n*n;};
vector<int> v(5, 0);
for (int i = 0; i < 5; i++){
v[i] = square(i);
}
}
The way that comes to mind is to break it into two steps. In this case std::iota will fill the vector with the inputs (0, 1, 2, etc). Then std::transform will perform your function square on each of the elements and replace them in the vector.
int main()
{
auto square = [] (int n) {return n*n;};
std::vector<int> v(5, 0);
std::iota(v.begin(), v.end(), 0);
std::transform(v.begin(), v.end(), v.begin(), square);
for (int i : v)
std::cout << i << ' ';
}
Output
0 1 4 9 16
Honestly this is the kind of thing that will be much more concise and streamlined once ranges are available, C++20 working example
int main()
{
auto square = [] (int n) {return n*n;};
for (int i : std::views::iota(0, 5) | std::views::transform(square))
std::cout << i << ' ';
}
For a vector there is easy way to calculate its index by subtracing pointers:
std::for_each(v.begin(),v.end(),
[&v,&square](auto& elem){ elem = square(&elem - &v[0]);});
by auto& elem you access original item of vector then index is calculated by &elem - &v[0] which is passed into square.

Erasing() an element in a vector doesn't work

I have a vector. I need to delete the last 3 elements in it.
Described this logic. The program crashes. What could be the mistake?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
If there are at least 3 items in the vector, to delete the last 3 items is simple -- just call pop_back 3 times:
#include <vector>
#include <iostream>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 3 && !v.empty(); ++i)
v.pop_back();
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
Output:
1 2
It is undefined behavior to pass the end() iterator to the 1-parameter erase() overload. Even if it weren't, erase() invalidates iterators that are "at and after" the specified element, making d invalid after the 1st loop iteration.
std::vector has a 2-parameter erase() overload that accepts a range of elements to remove. You don't need a manual loop at all:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
Live Demo
You could use a reverse_iterator:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
// start the iterator at the last element
vector<float>::reverse_iterator rit = X.rbegin();
// repeat 3 times
for(size_t i = 0; i < 3; i++)
{
rit++;
X.erase(rit.base());
}
// display all elements in vector X
for(float &e: X)
cout << e << '\n';
return 0;
}
There are few things to mention:
reverse_iterator rit starts at the last element of the vector X. This position is called rbegin.
erase requires classic iterator to work with. We get that from rit by calling base. But that new iterator will point to the next element from rit in forward direction.
That's why we advance the rit before calling base and erase
Also if you want to know more about reverse_iterator, I suggest visiting this answer.
First, X.end() doesn't return an iterator to the last element of the vector, it rather returns an iterator to the element past the last element of the vector, which is an element the vector doesn't actually own, that's why when you try to erase it with X.erase(d) the program crashes.
Instead, provided that the vector contains at least 3 elements, you can do the following:
X.erase( X.end() - 3, X.end() );
Which instead goes to the third last element, and erases every element after that until it gets to X.end().
EDIT: Just to clarify, X.end() is a LegacyRandomAccessIterator which is specified to have a valid - operation which returns another LegacyRandomAccessIterator.
This statement
if (i == 1) X.erase(d);
has undefined behavior.
And this statement tries to remove only the element before the last element
else X.erase(d - i);
because you have a loop with only two iterations
for (size_t i = 1; i < 3; i++) {
You need something like the following.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
auto n = std::min<decltype( v.size() )>( v.size(), 3 );
if ( n ) v.erase( std::prev( std::end( v ), n ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The program output is
1 2
The definition of end() from cppreference is:
Returns an iterator referring to the past-the-end element in the vector container.
and slightly below:
It does not point to any element, and thus shall not be dereferenced.
In other words, the vector has no element that end() points to. By dereferencing that non-element thru the erase() method, you are possibly altering memory that does not belong to the vector. Hence ugly things can happen from there on.
It is the usual C++ convention to describe intervals as [low, high), with the “low” value included in the interval, and the “high” value excluded from the interval.
A comment (now deleted) in the question stated that "there's no - operator for an iterator." However, the following code compiles and works in both MSVC and clang-cl, with the standard set to either C++17 or C++14:
#include <iostream>
#include <vector>
int main()
{
std::vector<float> X{ 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
std::vector<float>::iterator d = X.end();
X.erase(d - 3, d); // This strongly suggest that there IS a "-" operator for a vector iterator!
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
return 0;
}
The definition provided for the operator- is as follows (in the <vector> header):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
However, I'm certainly no C++ language-lawyer, and it is possible that this is one of those 'dangerous' Microsoft extensions. I would be very interested to know if this works on other platforms/compilers.

Functors and iteration trough vector

I'm trying to get into 'modern' C++, so I'm trying to learn how to properly use functors, and, subsequently, lambdas.
I think I've understood basic principle behind it, but I'm having trouble to understand how to acquire any element from a vector that is passed to my algorithm.
So, let's say I wish to create a Fibonacci sequence of length N...
struct Adder {
int operator()(int a, int b) {return a+b;}
};
const int N = 10;
int main() {
std::vector<int> vec = {0, 1};
vec.resize(N);
//Old Way
for(int i = 2; i < vec.size(); i++) {
vec[i] = vec[i-1] + vec[i-2];
}
std::transform(vec.begin(), vec.end(), vec.begin(), [](int i){return i*3;}); //single operator given to function, works
// std::transform(vec.begin()+2, vec.end(), vec.begin(), /*here two calls are needed , for a and b operators*/);
return 0;
}
Basically my question is how to activate functor defined in struct Adder? What is the proper way to pass two operators to him?
Adder::operator() should be const. And your Adder functor is unnecessary. Just use std::plus<>.
Since C++17, we have the transform overload that accepts two sequences. So we can do: (you can use Adder{} in place of std::plus<>{} if you want)
std::transform(vec.begin(), vec.end() - 2, vec.begin() + 1, vec.begin() + 2, std::plus<>{});
Minimal example: (live demo)
#include <algorithm>
#include <iostream>
#include <vector>
constexpr int N = 10;
int main()
{
std::vector<int> vec{0, 1};
vec.resize(N);
std::transform(vec.begin(), vec.end() - 2, vec.begin() + 1, vec.begin() + 2, std::plus<>{});
for (int x : vec)
std::cout << x << " ";
std::cout << "\n";
}

Vector comparison

Vector function emplace()
My emplace function does not work. Any help would be appreciated
vector <int> vec1;
vector <int> vec2(4,0);
vector <int>::iterator iter1;
vector <int>::iterator iter2;
srand(time(NULL));
for(i=0; i<5; i++){
n =rand()%10+1;
vec1.push_back(n);
}
for(iter1=vec1.begin();iter1<vec1.end();iter1++){
for(iter2=vec2.begin();iter2<vec2.end();iter2++){
if(*iter1<=*iter2){
//vec2.emplace(iter1,*iter1);
//print();
}
}
}
for(iter2=vec2.begin();iter2<vec2.end();iter2++){
Because vec2 starts populated with four values of 0, you will never find an element where *iter1 <= *iter2 unless *iter1 == 0.
Instead of zero-initializing it to avoid allocations, you want to reserve space.
vec2.reserve(vec1.size());
and then instead of a for loop you can use std::lower_bound to find the insert location:
#include <iostream>
#include <vector>
#include <algorithm>
void print_vec(const char* label, const std::vector<int>& vec) {
std::cout << label << ": ";
for (int v : vec) {
std::cout << v << ", ";
}
std::cout << "\n";
}
int main() {
std::vector <int> vec1 { 4, 1, 2, 2, 5 };
std::vector <int> vec2;
print_vec("v1", vec1);
vec2.reserve(vec1.size());
for (int v : vec1) {
auto it = std::lower_bound(vec2.begin(), vec2.end(), v);
if (it == vec2.end() || *it != v)
vec2.emplace(it, v);
print_vec("v2", vec2);
}
print_vec("Fin", vec2);
return 0;
}
Live demo: http://ideone.com/o5td9K
What you are trying to do is like insertion sort.
https://en.wikipedia.org/wiki/Insertion_sort
has the pseudo-code. At each step you will check every element in vector 2 and place the new element where it belongs (while loop).