This question already has answers here:
std::remove_if - lambda, not removing anything from the collection
(4 answers)
Closed 1 year ago.
I am trying to remove elements from a vector of ints using std::remove_if, but am not getting the required output.
Initial vector members: {0, 1, 2, 1, 3, 1, 4, 5, 1, 6, 1, 7, 1, 8, 1, 9}
Required Output: {0, 2, 3, 4, 5, 6, 7, 8, 9}
Actual Output: {0, 2, 3, 4, 5, 6, 7, 8, 9, 6, 1, 7, 1, 8, 1, 9}
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
class Equal
{
public:
Equal(int a): a_(a){}
bool operator()(int b)
{
return a_ == b;
}
private:
int a_;
};
int main()
{
std::vector<int> vi{0, 1, 2, 1, 3, 1, 4, 5, 1, 6, 1, 7, 1, 8, 1, 9};
std::cout << std::endl;
std::remove_if(vi.begin(), vi.end(), Equal(1));
for (const auto &i : vi) std::cout << i << " ";
return 0;
}
There are just as many elements in the vector before and after the call to
std::remove_if:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range.
... and std::remove_if returns an iterator to the start of the "removed" elements and you can use that iterator to actually erase the elements: See Erase–remove idiom
vi.erase(
std::remove_if(vi.begin(), vi.end(), Equal(1)), // returns iterator
vi.end() // erase to the end
);
Demo
Also note that std::vector got a new specialized function in C++20 that does both things, namely std::erase_if.
Example:
std::erase_if(vi, Equal(1));
Related
What is the right way to implement the function below to allow the caller to iterate over the range it returns?
#include <set>
#include <ranges>
std::set<int> set{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto find_range(int a)
{
//What type should I return?
return std::make_tuple(set.lower_bound(a - 3), set.upper_bound(a + 3));
}
int main()
{
for (int x : find_range(5)) {...}
}
The function returns a couple of iterators pointing to 2 and 9, so the loop should iterate over 2, 3, 4, 5, 6, 7, 8.
You can return a subrange like this
auto find_range(int a)
{
return std::ranges::subrange(set.lower_bound(a - 3),
set.upper_bound(a + 3));
}
Here's a demo.
I'm currently trying to find the minimum element of a 2D vector. I'm trying to practice using C++11 lambda functions and figured this might be good practice, but can't seem to get it compiling.
I'm aware that I could do the following:
vector<vector<int>> matrix = {
{1, 2, 3, 4, 5 },
{6, 7, 8, 9, 10 },
{5, 6, 8, 1, 12 },
{1, 7, 2, 4, 18 },
};
int result = std::numeric_limits<int>::max();
for(const auto& row : matrix)
{
int minElemInRow = *std::min_element(row.begin(), row.end());
result = std::min(result , minElemInRow);
}
return result;
but was wondering if the same could be done with a lambda function. Currently, this is my best attempt:
vector<vector<int>> matrix = {
{1, 2, 3, 4, 5 },
{6, 7, 8, 9, 10 },
{5, 6, 8, 1, 12 },
{1, 7, 2, 4, 18 },
};
return *std::min_element(matrix.begin(), matrix.end(),
[](const auto& row)
{
return *std::min_element(row.begin(), row.end());
});
I get the error: error C2672: 'operator __surrogate_func': no matching overloaded function found
How I feel it should be working is that the outer min_element will pass in a row at a time (which is just a reference to a vector), from which I can return the smallest, which will then be compared against other rows.
I thought that the problem might be that the lambda would be receiving an iterator to a vector of ints rather than a reference to the vector of ints, but dereferencing doesn't seem to be helping.
Is there a better way to be doing what I'm trying to do?
#assembly_wizard pointed out that min_element wants a predicate which can compare two of the item passed it. That is two rows. This leads to the following code:
vector<vector<int>> matrix = {
{1, 2, 3, 4, 5 },
{6, 7, 8, 9, 10 },
{5, 6, 8, 1, 12 },
{1, 7, 2, 4, 18 },
};
auto i = std::min_element(matrix.begin(), matrix.end(),
[](const auto& lhs, const auto& rhs)
{
return *std::min_element(lhs.begin(), lhs.end()) <
*std::min_element(rhs.begin(), rhs.end());
});
This will find the row with the smallest element. Though I can make that work by wrapping it in yet another std::min_element, that's getting way more complex than to be remotely helpful. If anyone has a better suggestion, I'd love to hear it!
I've compiled a working version that does what I've mentioned in the comments:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<std::vector<int>> matrix = {
{1, 2, 3, 4, 5 },
{6, 7, 8, 9, 10 },
{5, 6, 8, 1, 12 },
{1, 7, 2, 4, 18 },
};
std::vector<int> row_minimums(matrix.size());
std::transform(matrix.begin(), matrix.end(), row_minimums.begin(), [](const auto& row) {
return *std::min_element(row.begin(), row.end());
});
auto i = *std::min_element(row_minimums.begin(), row_minimums.end());
std::cout << "Minimum element is: " << i << std::endl;
}
See it in action on godbolt
This will take the minimum of each row separately, so we get row_minimums which is a vector of ints, and then it takes the minimum of these to get the final result between all the rows.
The only thing making this code worse than the for loop version, is that it keeps all of the row_minimums in memory at once, before running min_element on them. Unfortunately I don't know of a way to do this simultaneously, but I'm not the greatest STL expect, so maybe there is a way.
Other options you might consider is first concatenating the 2D matrix into a 1D vector and then using min_element on it, or the option you've included in your edit where you call min_element 3 times.
Also, this SO answer seems to have interesting info regarding solutions using the boost library which might be better, but I'm not sure exactly what they are.
Just a little simpler:
With std::for_each you iterate over each vector in matrix, and obtain the minimum element of them. As min is captured by reference, you get the min of all of them.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<std::vector<int>> matrix = {
{1, 2, 3, 4, 5 },
{6, 7, 8, 9, 10 },
{5, 6, 8, 1, 12 },
{1, 7, 2, 4, 18 },
};
int min = std::numeric_limits<int>::max();
std::for_each(matrix.begin(), matrix.end(),
[&min](const auto& v)
{
min = std::min(*min_element(v.begin(), v.end()), min);
}
);
std::cout << "Minimum element is: " << min << std::endl;
}
I'm refactoring some code and have decided that I would like to merge a two-dimensional array into a one-dimensional, larger array. The problem is now that I have some functions which take those smaller arrays as parameter and I would prefer to keep their signatures. Is it possible to call a function with only a part of a larger array?
f1 is what I currently have and f2 is what it should look like after refactoring:
#include <array>
void func(std::array<int const, 5> const& arr, int i);
void f1() {
static std::array<std::array<int const, 5>, 2> const arr{{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 0}}};
func(arr[0], 0);
func(arr[1], 1);
}
void f2() {
static std::array<int const, 10> const arr{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//TODO: call func with first and last 5 elements.
}
If you change your function to to take a range of elements as Peter commented, this becomes trivial. You would pass arr.begin() and arr.begin() + 5 for the first array and arr.begin() + 5, arr.end() for the second.
void func(int* b, int* e, int i);
You can also take a span just to make things cleaner. Here gsl::span is used but you can write your own if you want:
#include <gsl/span>
void func(gsl::span<int> s, int i);
static std::array<int const, 10> const arr{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
func( {arr.begin(), arr.begin() + 5}, 0 );
func( {arr.begin() + 5, arr.end()}, 1 );
I have an array of arrays of things
typedef std::vector<thing> group;
std::vector<group> groups;
things could be compared like so
int comparison(thing a, thing b);
where the return value is 0, 1 or 2
0 means that the things are not alike
1 means that they are alike and a is more specific or equal to b
2 means that they are alike and b is more specific or equal to a
and I am looking for a function that would return me a group that contains all things that appear in every group.
std::getgroup(groups.begin(), groups.end(), myComparisonFunction);
the problem is I have no idea what this function may be called, if it does even exist, or what the closest thing to it would be.
Eventually, what you want is an intersection. Luckily, there is std::set_intersection which almost does what you need. Here's a simple example on std::vector<std::vector<int>>. You can easily change it to work with your thing:
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> getGroup(const std::vector<std::vector<int>>& groups) {
std::vector<int> group;
std::vector<int> temp = groups[0];
std::sort(temp.begin(), temp.end());
for ( unsigned i = 1; i < groups.size(); ++i ) {
group = std::vector<int>();
std::vector<int> temp2 = groups[i];
std::sort(temp2.begin(), temp2.end());
std::set_intersection(temp2.begin(), temp2.end(),
temp.begin(), temp.end(),
std::back_inserter(group));
temp = group;
}
return group;
}
int main() {
std::vector<std::vector<int>> groups = { {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{1, 2, 3, 5, 6, 7, 8, 10},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{1, 3, 4, 5, 6, 9, 10},
{1, 2, 6, 7, 8, 9, 10},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} };
for ( auto g : getGroup(groups) )
std::cout << g << "\n";
return 0;
}
This will print:
1
6
10
Mathematica has a function called Range[] that does the following:
Range[0, 10]
Range[-10, 0]
Ant it prints:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0}
Does C++ have such a function?
None in the standard library, but from boost::range:
#include <iostream>
#include <iterator>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm/copy.hpp>
int main()
{
boost::copy(boost::irange(0, 11),
std::ostream_iterator<int>(std::cout, " "));
}
Output:
0 1 2 3 4 5 6 7 8 9 10
Seems easy enough to create one.
std::vector<int> range(int from, int to) {
std::vector<int> result;
result.reserve(to-from+1);
for (int i = from; i <= to; ++i) {
result.push_back(i);
}
return result;
}
For completeness, here is how you can do it with the C++11 standard library and lambdas:
vector<int> v;
int counter = -3; // The initial value
generate_n(
back_inserter(v) // Where to insert
, 10 // how many items
, [&counter] () -> int { return counter++; });
Here is a link to ideone with a demo.
There is only two libraries that provide lazy and O(1) memory numeric ranges:
Boost irange - only integral; no negative step(?); can not be assigned to other containers.
RO numeric_range - needs C++11
With SCC (C++ REPL) and RO:
scc 'range(0,10)'
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
scc 'range(-10,0)'
{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0}