jhammond
jhammond

Reputation: 2086

Removing Vector Items via a Lambda

I'm just messing around with some lambda expressions and I decided to attempt to remove duplicate elements from a vector. However, it isn't working. I put in some debug logging and it appears that std::count isn't returning the expected result. Any would would be greatly appreciated.

For reference, I know this isn't the most efficient way to remove an item from a vector! I was just experimenting with lambdas as I don't understand them as well as I would like to.

Thanks!

#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<int> v = { 0, 0, 1, 2, 4, 4, 4 };

    std::remove_if(v.begin(), v.end(), [&v](const int &x) 
    { 
        return std::count(v.begin(), v.end(), x) > 1;
    });

    std::cout << "\n\nResult:\n";
    for (const auto& i : v) { std::cout << i << std::endl; }

    return 0;
}

Upvotes: 2

Views: 3193

Answers (1)

Barry
Barry

Reputation: 303206

That's because remove_if doesn't actually remove elements:

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.

That's why it returns an iterator, so you can then:

A call to remove is typically followed by a call to a container's erase method, which erases the unspecified values and reduces the physical size of the container to match its new logical size.

That is:

v.erase(std::remove_if(v.begin(), v.end(), [&v](const int &x) 
{ 
    return std::count(v.begin(), v.end(), x) > 1;
}), v.end());

This is known as the Erase-remove idiom.

Note that if all you want to do is remove duplicates, and you don't care about preserving the order, you could use std::sort and std::unique (you need to sort because unique only "removes" consecutive duplicate elements):

std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());

Upvotes: 4

Related Questions