views:

389

answers:

5

In Ruby I can do:

 [1,2,3,4].include?(4) #=>True

In Haskell I can do :

4 `elem`   [1,2,3,4]   #=> True

What should I do in C++?

+20  A: 

Here an example using find:

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

int main() {
        std::vector<int> Num(4);
        //insert values
        Num[0]=1;
        Num[1]=2;
        Num[2]=3;
        Num[3]=4;
        std::vector<int>::iterator p = find(Num.begin(), Num.end(), 4);
        if (p == Num.end())
           std::cout  << "Could not find 4 in the vector"  << std::endl;
        else
           std::cout  << "Have found 4 in the vector"  << std::endl;
        return 0;
}
Burkhard
std::find to be precise :)
forcey
Now it should be complete :)
Burkhard
@forcey, No need to fully qualify `find` according to Koenig lookup (C++ Standard 3.4.2).
Kirill V. Lyadvinsky
@Jla3ep: now I had to try it myself. Without the using namespace std; it does not compile. I'm using g++ (GCC) 4.1.2.
Burkhard
Burkhart: you forgot one `std::` in front of the `vector<int>::iterator`. Qualifying `find` is really not necessary here due to argument-dependend lookup (or Koenig lookup). However, that's an implementation detail. For all we know, `vector<int>::iterator` *could* resolve to `int*` or a type not found in the `std` namespace and lookup would fail. So yes, to be absolutely standards compliant, you need to open (or qualify) the namespace.
Konrad Rudolph
I also would have to qualify cout and endl without the using namespace std;, would I not?
Burkhard
@Burkhard: Yes, you would. And frankly, I'd find it a lot better than the using directive.
sbi
It's worth noting that .find works in other STL containers too : maps for instance. Rule of thumb is : if the iterator points to .end() of the container (an item following the last item in the container) the target value was not found.
Maciek
@Maciek: I wouldn't really call this a "rule of thumb". It's casted in stone, after all. `:)`
sbi
+1  A: 

To get similar syntax as in OP's question:

std::vector<int> x;

if ( count( x.begin(), x.end(), VAL_TO_FIND ) ) {
 // found
} else {
 // not found 
}
Kirill V. Lyadvinsky
Requires iterating through the entire data structure.
Brian Gianforcaro
Yes, but it has the same complexity as find has = O(n).
Kirill V. Lyadvinsky
There is no reason to iterate through a data structure of 100,000 objects when the one i want to know is inside the data structure is at index one. std::find's best case run time kicks' the pants of of std:count for seeing if an object just exists in a data structure. In all cases find is better or as good as count. Their is no reason to use it.
Brian Gianforcaro
For small arrays that is not big deal. For large arrays you should consider sorting them(or use boost::multi_index which is RB-tree). Then you'll search for O(n*log n) on RB-tree, or for O(log n) on plain sorted array.
Kirill V. Lyadvinsky
The reason to use count is to get same syntax as in question. I mentioned it in the answer. Usually using `find` is a good choice.
Kirill V. Lyadvinsky
A: 

You could use std::set This has a find() method.

teambob
Every container has a `find` method. It's just usually a nonmember.
jalf
There is a find algorithm which can be used with any container but the std::set class is designed to be efficient for typical set operations.For example the generic std::find() takes O(n) to find a value, whereas std::set::find() will take O(ln(n)) to find a value.
teambob
The STL philosophy can be summarized as : If it's a member, it's because the class was intended to do so. If it's a non-member, it's because it's possible. See e.g. random iterators (`operator+`) and other iterators (`std::advance`)
MSalters
@teambob: That's the way it is in theory. Note that in practice there often is a deviation from the theory, usually towards the side of `std::vector` which plays much better with processor caches. OTOH, if `std::set` fits the bill from an algorithmic POV, I`d take this until profiling shows it comes with a significant performance cost.
sbi
@sbi: actually the minimum O() performance is specified in the standard, so it is not just theory. I agree with you that if a std::vector suits the needs of the majority of the code the std::find(). But if the OP is only dealing with this list of numbers as set it would be good to use std::set()We should use the right tool for the job. std::set is the optimal tool for the problem the OP described. When the OP has to fit this problem into a larger piece of code std::set may not be the best tool for the job.
teambob
Big O notation tells you about how an algorithm scales, not how to compare two different algorithms. When comparing two different algorithms you need to consider the constant factors. For small n, an algorithm that scales O(n) might be much better than one that scales O(ln n). Using a set involves a larger constant factor and also has a memory overhead. There are also other considerations: How often does the set of numbers change? For an infrequently changing set that can be sorted it is hard to beat a binary search.
janm
@teambob: I know Big O, too. nevertheless, due to aggressive caching in modern processors and due to the data being more local in `std::vector`, it will, in practice, often perform better even though, in theory, some other container (e.g., `std::list` with a low locality of data) should excel.
sbi
@janm: Although if you don't know the approximate final size of the data set (so you can use std::vector::reserve() ) the potential need to copy during reallocation of the vector may offset the caching advantages.All I did was to provide an *alternative* solution to the problem that no-one else mentioned. It is extremely important to know your tools - and I am certainly not suggesting that one tool should be used for everything. And I agree std::vector paired with std::find() or std::binary_search() may be more suited in this case - depending on what the data really is.
teambob
Sure. My point isn't that using std::set is an invalid solution; it is certainly a possible choice. My point is that saying std::set is better that std::vector because it the find operation is O(ln n) vs. O(n) is incorrect. On using vector::reserve: Even without using reserve you can do well. Sequential memory access, locality of reference, low constant factor. But the real point is: "It Depends."
janm
+8  A: 

There isn't a built-in function doing exactly that. There is std::find which comes close, but since it doesn't return a bool it is a bit more awkward to use.

You could always roll your own, to get syntax similar to JIa3ep's suggestion, but without using count (which always traverses the entire sequence):

template <typename iter_t>
bool contains(iter_t first, iter_t last, typename iter_t::value_type val){
    return find(first, last, val) != last;
}

Then you can simply do this to use it:

std::vector<int> x;

if (contains(x.begin(), x.end(), 4)) {...}
jalf
Is this code supposed to compile?
GRB
In theory. I haven't tested it. ;)What problems are you seeing with it?
jalf
Well the two compile-error issues I see are that you combine the constructor and `operator()` overload in one call (need to do `contains(x.begin(), x.end())(4)`) but then on top of that since `contains` is a functor it doesn't benefit from template type inference (so assuming you're searching a `vector<int>` you'd have to call `contains` with `contains<vector<int>::iterator>(...)(...)`). Finally as a logic error you probably want `find(first, last, val)`, not `find(first, first, val)`.
GRB
doh, you're right. Teach me not to write code just after waking up. And I wonder why I made it a functor in the first place. I'd better fix it then. ;)
jalf
there we go. Much shorter too. Thanks for pointing out those problems.
jalf
+1 no problem, helping you out teaches me as much as it does you (though as you say it's not that you didn't already know this stuff, it was probably just drowziness :D )
GRB
C++0x has std::any_of which returns a bool and will do this just fine. This is in <algorithm> in visual studio 2010.
Rick
+1  A: 

If the vector is ordered, you can also use std::binary_search.

std::binary_search(vec.begin(), vec.end(), 4)  // Returns true or false
janm