tags:

views:

50

answers:

2

From the title you'd almost assuredly think use set_union to create a list and then check if it's empty. However, the objects I'm comparing are "expensive" to copy. I've looked at includes but that only works if all the items of one list are found in another. I've also looked at mismatch but rejected it for obvious reasons.

I can and have written my own function which assumes both lists are sorted but I'm wondering if an efficient function already exists in the STL. (Project is forbidden to use third-party libraries including Boost and TR1, don't ask.)

+1  A: 

Is find_first_of() what you're after?

Oli Charlesworth
This is why I love SO.
wheaties
@wheaties: This is why I love http://cplusplus.com, where I got the answer from...!
Oli Charlesworth
Lol, yes but it's still an operation of M*N, with ordering I thought there might be a snazzier function. Oh well. Rather use STL than roll my own.
wheaties
+3  A: 

If the sets are unsorted, then you can use find_first_of for an O(N*M) algorithm.

If they are sorted (which would be required for set_intersection anyway), then you can iterate over one set calling equal_range in the other for every element. If every returned range is empty, there is no intersection. Performance is O(N log M).

However, there is no excuse not to have O(N+M) performance, right? Nothing is copied by set_intersection if it's passed a dummy iterator.

struct found {};

template< class T > // satisfy language requirement
struct throwing_iterator : std::iterator< std::output_iterator_tag, T > {
    T &operator*() { throw found(); }
    throwing_iterator &operator++() { return *this; }
    throwing_iterator operator++(int) { return *this; }
};

template< class I, class J >
bool any_intersection( I first1, I last1, J first2, J last2 ) {
    try {
        throwing_iterator< typename std::iterator_traits<I>::value_type > ti;
        set_intersection( first1, last1, first2, last2, ti );
        return false;
    } catch ( found const& ) {
        return true;
    }
}

This provides for early exit. You could alternately avoid the exception and just have the iterator remember how many times it was incremented, and no-op the assignment.

Potatoswatter
`equal_range` only takes a single element (or predicate) so, I'm not sure how you mean it should be used in paragraph two. I like the use of `set_intersection`, though.
Charles Bailey
@Charles: The same way `find_first_of` works: by iterating over one set.
Potatoswatter
`find_first_of` takes two ranges so it's one call. I may just be being slow but what does `equal_range` give you that, say, `find` doesn't given that you'll have to do some sort of loop?
Charles Bailey
@Charles: `equal_range` works on a sorted sequence and is O(log N). `find` works on unsorted and is O(N). Clarified answer.
Potatoswatter
True, I only meant from the complexity of the required supporting code. OK, what advantage over, say, `binary_search`?
Charles Bailey
@Charles: I forgot about `binary_search`, lol. All it does is compare the `first` and `second` of `equal_range`'s result, which is what's needed here.
Potatoswatter
OK, post-edit, I think I'm with you. You did mean that you need to iterate over one set searching in the other.
Charles Bailey
This is nice, didn't even think to give a dummy type iterator. I don't like that you're using an exception to do unexceptional behavior but all in all I think it's terrific.
wheaties
@wheaties: you'll have to decide whether the likely performance benefit of an early-exit (in the case where the intersection is non-empty) is worth the argument over what exceptions "are for". If it helps I suppose you could argue that "I don't want this algorithm to run to completion" is an exceptional circumstance from the POV of the algorithm, if not from the POV of the caller (hence you catch it - any exception caught and not rethrown can't be all that "exceptional" from the POV of the catcher). Or you could just copy-paste-modify your implementation of `set_intersection`.
Steve Jessop