5

I can't infer I can use std::set_difference from documentation, because it says sets should be ordered, which means they are not sets, but lists. Also all examples are about ordered lists, not sets.

How to know the truth?

NutCracker
  • 11,485
  • 4
  • 44
  • 68
Dims
  • 47,675
  • 117
  • 331
  • 600

2 Answers2

9

std::set_difference is for use with arbitrary sorted inputs (pre-sorted std::vectors, std::lists, std::deques, plain array, etc.), it just happens to work with std::set (which is sorted) too.

If you're working with std::unordered_set (or std::set, and you're okay with operating in place), you'd just use the erase method to remove all elements from one such set from another to get the difference, e.g.:

for (const auto& elem : set_to_remove) {
    myset.erase(elem);
}

You can also do it into a new set with std::copy_if; the recipe there is trivially adaptable to the case of symmetric difference (it's just two calls to std::copy_if, where each one runs on one input set, and is conditioned on the element not existing in other input set).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • The code in this example results in segfaults. This usage of `std::set::erase` only applies to iterators that are *part of* `myset`. See [here](https://en.cppreference.com/w/cpp/container/set/erase): "Removes the elements in the range `[first; last)`, which must be a valid range in `*this`." – sasquires Jul 30 '20 at 01:21
  • @sasquires: Oof, my mistake. It's not as elegant, but I replaced the bad code with a version that just iterates `set_to_remove` and use the by-value version of `erase`. Thanks for catching that! – ShadowRanger Jul 30 '20 at 01:30
3

std::set is sorted. Check out the docs:

std::set is an associative container that contains a sorted set of unique objects of type Key. Sorting is done using the key comparison function Compare. Search, removal, and insertion operations have logarithmic complexity. Sets are usually implemented as red-black trees.

Therefore, you can use it in a same way as any other container that provides the required interface. The difference between std::set and e.g. std::vector is that std::set is sorting its elements on insertion and in case of std::vector you need to use std::sort function to get its elements sorted.

For example, if you need to std::set_difference for std::unordered_set, you can do it like this:

#include <set>
#include <iostream>
#include <algorithm>
#include <unordered_set>

int main() {
    std::unordered_set<int> a {3, 1, 4, 6, 5, 9};
    std::unordered_set<int> b {3, 1, 4};

    std::set<int> c;
    std::set<int> d;
    std::copy(a.begin(), a.end(), std::inserter(c, c.end()));
    std::copy(b.begin(), b.end(), std::inserter(d, d.end()));

    std::vector<int> diff;

    std::set_difference(c.begin(), c.end(), d.begin(), d.end(), 
                        std::inserter(diff, diff.begin()));

    for (auto const i : diff)
        std::cout << i << ' ';

    return 0;
}

See live

NutCracker
  • 11,485
  • 4
  • 44
  • 68