20

I am trying to find a simple way to check whether a vector is a subset of another without sorting the order of elements in the vector. Both the vectors contain random number elements in them.

std::includes seems to work only for sorted ranges. How can I accomplish this?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Praveen
  • 1,781
  • 6
  • 26
  • 32

4 Answers4

35

Copy the vectors. Sort the copies. Then use std::includes on the copies.

template <typename T>
bool IsSubset(std::vector<T> A, std::vector<T> B)
{
    std::sort(A.begin(), A.end());
    std::sort(B.begin(), B.end());
    return std::includes(A.begin(), A.end(), B.begin(), B.end());
}
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • 10
    "I am trying to find a simple way to check whether a vector is a subset of another without sorting the order of elements in the vector." If sorting is the answer, your question was very, very broken. – Lightness Races in Orbit Aug 02 '11 at 02:14
  • @Benjamin: Agreed, there's no reason why this should be downvoted. This is the smartest way of doing this out of all the answers given. If the OP truly wants to check if two things are subsets of each other without modifying the data, this is the way to go. This is literally probably about 5 lines of code in all. If the exact requirement was "I need to check if one is a subset of the other, with `O(1)` memory usage and without displacing the data of either vectors" the answer would be one of the two below. – Mike Bailey Aug 02 '11 at 02:19
  • 4
    @Benjamin: Because you didn't answer the question of "find... without sorting..." as Tomalak stated. – Andrew Rasmussen Aug 02 '11 at 02:24
  • 1
    @arasmussen: It seems like the "without sorting" requirement is a symptom of an underlying issue that the OP never quite got at. He described something he wanted to do but not what he was actually trying to accomplish. I've seen questions (and I've been guilty of asking such things) where the poster asked for one thing thinking it was the solution but where there was a much simpler solution that didn't require strange requirements. – Mike Bailey Aug 02 '11 at 02:27
  • 1
    @arasmussen: The question wasn't "find... without sorting...". If it was, I would have voted to close the question because it is an arbitrary requirement that is not applicable to real life programming. The requirement was that the OP didn't want his *own* vector sorted. That *is* a requirement that could be applicable to real life programming, so I answered *that* question. – Benjamin Lindley Aug 02 '11 at 02:28
  • @Benjamin: If you're going to transparently modify the question that you're answering, at least mention that in your answer as a disclaimer. – Lightness Races in Orbit Aug 02 '11 at 02:36
  • @Tomalak: I didn't modify the question, I just read it differently than you. – Benjamin Lindley Aug 02 '11 at 02:36
  • Agree with Benjamin. There's really only one good reason why you wouldn't want to sort the original vectors: if the original order of the vectors had business relevance. So you sort a copy. – MSalters Aug 02 '11 at 07:50
9

My answer assumes that when you say "subset", you are really searching more for the equivalent of a "substring"; that is, maintaining order of elements during the search.


Ultimately, I can't see how you could do this in anything less than O(n*m). Given that, you can just roll your own pretty simply:

template <typename T1, typename T2>
bool contains(std::vector<T1> const& a, std::vector<T2> const& b) {
   for (typename std::vector<T1>::const_iterator i = a.begin(), y = a.end(); i != y; ++i) {
      bool match = true;

      typename std::vector<T1>::const_iterator ii = i;
      for (typename std::vector<T2>::const_iterator j = b.begin(), z = b.end(); j != z; ++j) {
          if (ii == a.end() || *j != *ii) {
              match = false;
              break;
          }
          ii++;
      }

      if (match)
         return true;
   }

   return false;
}

Live demo.

(You could probably be more creative with the template parameters.)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
3

This is assuming duplicates do NOT matter. So if you have two instances of the number 99 in vector a, then as long as vector b has at least one instance of the number 99, then it will be declared as a subset.

bool isSubset(const std::vector<int>& a, const std::vector<int>& b)
{
    for (std::vector<int>::const_iterator i = a.begin(); i != a.end(); i++)
    {
        bool found = false;

        for (std::vector<int>::const_iterator j = b.begin(); j != b.end(); j++)
        {
            if (*i == *j)
            {
                found = true;
                break;
            }
        }

        if (!found)
        {
            return false;
        }
    }

    return true;
}
Andrew Rasmussen
  • 14,912
  • 10
  • 45
  • 81
0

With no sorting...

template <typename T>
bool isSubsetOrEqual(std::vector<T> const& a, std::vector<T> const& b) {
   for(auto const& av:a){
      if(std::find(b.begin(),b.end(),av)==b.end())
          return false;
   }
   return true;
}
thayne
  • 426
  • 5
  • 18