5

I have a vector of elements. I want to populate a set using the elements of this vector that match a certain condition. Can I do this using one line, or in any way that is more concise than the below?

// given vector<int> v

set<int> s;
for (const int& i : v)
{
    if (/* some condition on i*/)
        s.insert(i);
}

For example, something along the line of:

// given vector<int> v

set<int> s;
s.insert(v.filter(/* lambda here*/));

It goes without saying that the v.filter method should return an iterator, not a separate populated vector, for performance reasons.

nappyfalcon
  • 909
  • 1
  • 10
  • 17

3 Answers3

13

You can use std::copy_if with a lambda and std::inserter to insert the values into the set. That looks like

std::copy_if(v.begin(), v.end(), std::inserter(s, s.begin()), [](auto val) { return val == some_condition; });
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
3

With range-v3, it would be

set<int> s = v | ranges::view::filter([](int e){ return cond(e); });

or simply (if cond already exist)

set<int> s = v | ranges::view::filter(cond);
Jarod42
  • 203,559
  • 14
  • 181
  • 302
3

+1 for the std::copy_if() solution that, IMHO, is the natural solution for this problem.

Just for fun, I propose a different solution based on std::for_each()

std::set<int> s;

std::for_each(v.cbegin(), v.cend(),
              [&](int i) { if ( /* some condition */ ) s.insert(i); }); 
max66
  • 65,235
  • 10
  • 71
  • 111
  • I don't see the gain of `for_each` now that we have for range. – Jarod42 Apr 11 '18 at 16:31
  • 1
    @Jarod42 - not a gain at all, IMHO; it's just for fun (to show an alternative way to make the same thing) when the OP ask for a solution "in a single line of code" (but I suppose also the for range can be written and considered as a single line of code) – max66 Apr 11 '18 at 16:43