i want to iterate over a vector of ints and remove all even numbers.
Example:
std::vector<int> v = {5,2,9,3,8}
auto it = std::remove_if(v.begin(),v.end(),
std::bind(std::bind(std::equal_to<int>(),_1,0),
std::bind(std::modulus<int>(),_1,2)));
The expected result should be {5,9,3}
But it is {5,8,9,3,8}
I think the Iterator is already at the end before performing all functions in bind and remove.
I know how to solve it differently but i want to know how to use the nested form and how it works with iterators
In VS2015, your code leaves v containing {5, 9, 3, 3, 8}.
std::remove_if() returns an iterator to the first unused element in the vector, use that to truncate the vector :
v.erase(it, v.end());
After that, v contains {5, 9, 3}
On a side note, if you want to use a lambda instead of bind you can do it like this:
std::vector<int> v = { 5, 2, 9, 3, 8 };
auto it = std::remove_if(v.begin(), v.end(), [](int val) { return val % 2 == 0; });
v.erase(it, v.end());
Related
Take this vector:
std::vector<int> v = {1, 2, 3, 4, 5};
Let's say I want to remove some elements of a vector at some arbitrary indices: 0, 1, and 3. It's tedious to have to write something like this:
v.erase(v.begin());
v.erase(v.begin());
v.erase(v.begin() + 1);
Is there any standard function that takes in an arbitrary number of indices to erase from a vector? Something like this: v.erase(0, 1, 3);
Yes and no.
There's nothing that deals with indices. There's also nothing that deals with arbitrary elements.
But you can erase multiple items that form a contiguous range at once. So you can coalesce your first two calls to erase into one (and probably about double the speed in the process).
// erase the first two elements
v.erase(v.begin(), v.begin() + 2);
If you want to erase first three element so for this you can run.
std::vector<int> v = {1, 2, 3, 4, 5};
v.erase(v.begin(),v.begin()+3);
or,
v.erase(v.begin(),v.end()-2);
Let's say I have a a vector<vector<int>>. I want to use ranges::transform in such a way that I get
vector<vector<int>> original_vectors;
using T = decltype(ranges::views::transform(original_vectors[0], [&](int x){
return x;
}));
vector<int> transformation_coeff;
vector<T> transformed_vectors;
for(int i=0;i<n;i++){
transformed_vectors.push_back(ranges::views::transform(original_vectors[i], [&](int x){
return x * transformation_coeff[i];
}));
}
Is such a transformation, or something similar, currently possible in C++?
I know its possible to simply store the transformation_coeff, but it's inconvenient to apply it at every step. (This will be repeated multiple times so it needs to be done in O(log n), therefore I can't explicitly apply the transformation).
Yes, you can have a vector of ranges. The problem in your code is that you are using a temporary lambda in your using statement. Because of that, the type of the item you are pushing into the vector later is different from T. You can solve it by assigning the lambda to a variable first:
vector<vector<int>> original_vectors;
auto lambda = [&](int x){return x;};
using T = decltype(ranges::views::transform(original_vectors[0], lambda));
vector<T> transformed_vectors;
transformed_vectors.push_back(ranges::views::transform(original_vectors[0], lambda));
It is not possible in general to store different ranges in a homogeneous collection like std::vector, because different ranges usually have different types, especially if transforms using lambdas are involved. No two lambdas have the same type and the type of the lambda will be part of the range type. If the signatures of the functions you want to pass to the transform are the same, you could wrap the lambdas in std::function as suggested by #IlCapitano (https://godbolt.org/z/zGETzG4xW). Note that this comes at the cost of the additional overhead std::function entails.
A better option might be to create a range of ranges.
If I understand you correctly, you have a vector of n vectors, e.g.
std::vector<std::vector<int>> original_vector = {
{1, 5, 10},
{2, 4, 8},
{5, 10, 15}
};
and a vector of n coefficients, e.g.
std::vector<int> transformation_coeff = {2, 1, 3};
and you want a range of ranges representing the transformed vectors, where the ith range represents the ith vector's elements which have been multiplied by the ith coefficient:
{
{ 2, 10, 20}, // {1, 5, 10} * 2
{ 2, 4, 8}, // {2, 4, 8} * 1
{15, 30, 45} // {5, 10, 15} * 3
}
Did I understand you correctly? If yes, I don't understand what you mean with your complexity requirement of O(log n). What does n refer to in this scenario? How would this calculation be possible in less than n steps? Here is a solution that gives you the range of ranges you want. Evaluating this range requires O(n*m) multiplications, where m is an upper bound for the number of elements in each inner vector. I don't think it can be done in less steps because you have to multiply each element in original_vector once. Of course, you can always just evaluate part of the range, because the evaluation is lazy.
C++20
The strategy is to first create a range for the transformed i-th vector given the index i. Then you can create a range of ints using std::views::iota and transform it to the inner ranges:
auto transformed_ranges = std::views::iota(0) | std::views::transform(
[=](int i){
// get a range containing only the ith inner range
auto ith = original_vector | std::views::drop(i) | std::views::take(1) | std::views::join;
// transform the ith inner range
return ith | std::views::transform(
[=](auto const& x){
return x * transformation_coeff[i];
}
);
}
);
You can now do
for (auto const& transformed_range : transformed_ranges){
for (auto const& val : transformed_range){
std::cout << val << " ";
}
std::cout<<"\n";
}
Output:
2 10 20
2 4 8
15 30 45
Full Code on Godbolt Compiler Explorer
C++23
This is the perfect job for C++23's std::views::zip_transform:
auto transformed_ranges = std::views::zip_transform(
[=](auto const& ith, auto const& coeff){
return ith | std::views::transform(
[=](auto const& x){
return x * coeff;
}
);
},
original_vector,
transformation_coeff
);
It's a bit shorter and has the added benefit that transformation_coeff is treated as a range as well:
It is more general, because we are not restricted to std::vectors
In the C++20 solution you get undefined behaviour without additional size checking if transformation_coeff.size() < original_vector.size() because we are indexing into the vector, while the C++23 solution would just return a range with fewer elements.
Full Code on Godbold Compiler Explorer
I want to test a function that reorders array elements so that even numbers will be at the beginning of a std::vector:
void EvenOdd(vector<int>* A_ptr);
This is a working test I wrote:
MATCHER(first_odd_implies_second_odd, "first element is odd and second even!")
{
auto isOdd = [](auto x) -> bool { return x & 1; };
return !isOdd(arg[0]) || isOdd(arg[1]);
}
TEST(Arrays_EvenOdd, simpleTest)
{
std::vector<int> v{ 1, 2, 4, 8, 9, 6, 3 };
EvenOdd(&v);
for (auto it = v.begin(); it != v.end() - 1; ++it)
{
ASSERT_THAT(it, first_odd_implies_second_odd());
}
}
After the call to EvenOdd() I expect v to be i.e. [6, 2, 4, 8, 9, 1, 3]. All the even numbers are before any odd number.
Is there a way to remove the for loop from the Arrays_EvenOdd.simpleTest test?
I'm looking for something to apply first_odd_implies_second_odd matcher to the range:
[v.begin(), v.end() - 1]
IMO tests don't have to contain any logic (e.g. that would require usage of std::is_partitioned) but should rather use Arrange/Act/Assert approach where you state your inputs, execute code under test and compare output with the expected output that can be hardcoded.
Using functions to generate expectations (rather than hardcoded values) can be dangerous because if you end up using the same algorithm inside you function and to generate the expected output, then if the underlying algorithm doesn't work properly, both your expected and actual output will be incorrect (but the same, so the test would pass!). That rather won't happen when using std algos, but it might be tempting to generate the expected output with the same algorithm that is under test - which would be mistake.
For practice, I am trying to copy the first 4 entries different than 2 from a vector of integers using copy_if.
This seems to work but if there is a better way of writing this lambda then I'd like to learn the proper way. Cheers.
vector<int> first_vector = {2,8,50,2,4,5,9,12};
vector<int> second_vector (first_vector.size());
int count_elem=0;
auto it = copy_if(first_vector.begin(),first_vector.end(),second_vector.begin(),
[&count_elem]
(int i){
if(i!=2 && count_elem!=4)
{
count_elem++;
return 1;
}
return 0;});
Since you are not copying all of the values from first_vector to second_vector, you should not initialize second_vector to hold the same number of elements as first_vector. You are creating more elements than you want, where the extra elements are value-initialized to 0.
I would suggest reserve()'ing the size of second_vector instead and then use std::back_inserter as the destination iterator to copy to. That way, second_vector ends up with only the values you want pushed and nothing else.
That would also eliminate the need for the count_elem variable. You can use second_vector.size() to know how many values have been pushed into the vector.
std::vector<int> first_vector = {2, 8, 50, 2, 4, 5, 9, 12};
std::vector<int> second_vector;
second_vector.reserve(4);
std::copy_if(
first_vector.begin(), first_vector.end(),
std::back_inserter(second_vector),
[&](int i){
return ((i != 2) && (second_vector.size() < 4));
}
);
Do note, however, that this use of std::copy_if() will iterate through the entire first_vector, it will not stop iterating once 4 values have been pushed to second_vector. It would be more efficient to simply run your own loop instead so you can break it as soon as possible:
std::vector<int> first_vector = {2, 8, 50, 2, 4, 5, 9, 12};
std::vector<int> second_vector;
second_vector.reserve(4);
for(int i : first_vector) {
if (i != 2) {
second_vector.push_back(i);
if (second_vector.size() == 4)
break;
}
}
I want to check whether given two integers in a specific order are in the same order in a given integer array.
I wonder whether there is an easy way to do this like a built-in CPP method.
If there is no built-in method, suggest me an efficient way to do this as I have a few sets of two integers (not only one set) to check over one array.
given two numbers: 8 3
given array: 2 8 6 1 3 9
output: YES
You could do something like
bool check(std::pair<int, int> numbers = {8, 3},
std::array<int, 6> arr = {2, 8, 6, 1, 3, 9}) {
if (numbers.first != numbers.second)
return std::find(std::find(std::begin(arr), std::end(arr), numbers.first), std::end(arr), numbers.second) == std::end(arr);
return std::count(std::begin(arr), std::end(arr), numbers.first) >= 2;
}
If both numbers are different the inner find searches for the first value. The outer find starts at the position of the first value and searches for the second value.
Else the count is checked.
You could also try:
std::array<int, 6> content = {2, 3, 6, 1, 8, 9};
auto lookup = [content](int a, int b)
{
return std::distance(std::find(content.begin(), content.end(), a), std::find(content.rbegin(), content.rend(), b));
};
lookup(8, 3);
lookup will be positive if 8 comes before 3 and negative otherwise.
Search the entire container to find the first one. Search from the position of the first one to the end of the container to find the second one. If that search succeeds, they're in the expected order. If not, they're not.
int first_value = 8;
int second_value = 3;
std::array<int, 6> values = { 2, 8, 6, 1, 3, 9 };
auto first_pos = std::find(values.begin(), values.end(), first_value);
if (first_pos != values.end())
++first_pos;
auto second_pos = std::find(first_pos, values.end(), second_value);
if (second_pos != values.end())
std::cout << "YES\n";
Use adjacent find. I suppose find_if could also do the job.