4

This compiles and runs ok on Visual C++ 2010 Express but it only checks against the [2] element: "Fish".

int main() { vector<string> words; string temp; vector<string> disliked(3); disliked[0] = "Broccoli"; disliked[1] = "Mushrooms"; disliked[2] = "Fish"; while (cin >> temp) words.push_back(temp); cout << "Number of words: " << words.size() << endl; for (int i=0; i<words.size(); ++i) { if (words[i]!=disliked[2]) cout << words[i] << " "; else cout << "BLEEP" << " "; } cout << endl; keep_window_open(); return 0; } 

How do I make it check against ALL vector elements without typing:

if (words[i]!=disliked[0] && words[i]!=disliked[1] && words[i]!=disliked[2]) 

? Any other advices of how to make it better or more elegant?

3
  • 1
    I happen to like broccoli, mushrooms, and fish. Commented Oct 30, 2010 at 9:39
  • Me too! Don't worry, it's only a silly exercise in Stroustrup's book about Programming with C++. :) Commented Oct 30, 2010 at 9:42
  • I like mushrooms and fish more than broccoli. Broccoli is ok too though. Just not as good as mushrooms and fish. Commented Oct 30, 2010 at 12:14

5 Answers 5

10
if (std::find(disliked.begin(), disliked.end(), words[i]) == disliked.end()) { cout << words[i] << " "; } else { cout << "BLEEP" << " "; } 

If you replace std::vector<string> disliked(3); with std::set<string> disliked; it works faster.

std::set<string> disliked; disliked.insert("Broccoli"); disliked.insert("Mushrooms"); disliked.insert("Fish"); //.... if (disliked.find(words[i]) == disliked.end()) { cout << words[i] << " "; } else { cout << "BLEEP" << " "; } 
Sign up to request clarification or add additional context in comments.

2 Comments

+1, just fix the typo with the std::set constructor. It shouldn't take any arguments.
@Charles: I took the liberty of fixing it.
2

Well you can simply use std::find to search for the word in the vector. But in general, vectors aren't meant for this sort of random-access lookup. You might want to consider using an std::set to store the foods you don't like.

Then you can just say:

std::set<std::string> dislike; dislike.insert("Broccoli"); dislike.insert("Mushrooms"); dislike.insert("Fish"); ... if (dislike.find("whatever") != dislike.end()) std::cout << "BLEEP" << std::endl; 

Also, consider using an alternative expletive to "BLEEP".

6 Comments

You say "vectors aren't meant for this sort of lookup". I wonder why. Actually, the expression if (words[i]!=disliked[0,2]) /* notice the 0 */ is accepted and can be run but it still gives me a Bleep only for Fish.
Because when you search the vector for a word, you have to scan through the entire vector. This is what the std::find function actually does, resulting in O(N) running time. With std::set, each lookup is only O(Log(N)) running time, which is much faster. Although for only 3 items there won't be any noticeable difference.
Also, that disliked[0,2] isn't doing what you think it's doing. It doesn't mean you're actually comparing words[i] to elements 0 through 2 in the vector. It's just a (misuse) of the (mostly useless) comma operator from C. See en.wikipedia.org/wiki/Comma_operator
Thank you so much! This is the most difficult part in learning any language I guess. Sometimes the compiler allows you do things without complaining and you think it has worked the way you implied.
@Kensai: You need to crank up your compiler's warning levels. Then it should say "WARNING: left operand of comma operator has no effect" or something like that.
|
2

C++0x introduces three algorithms that you might want to check out: all_of, any_of and none_of.

#include <algorithm> #include <functional> for (vector<string>::size_type i = 0; i < words.size(); ++i) { if (any_of(disliked.begin(), disliked.end(), bind2nd(equal_to<string>(), words[i]))) { cout << "BLEEP" << " "; } else { cout << words[i] << " "; } } 

But as Alexey already pointed out, in this specific case, you are probably better off with a std::set. You could also do a binary_searchon the vector, but then you have to make sure its sorted.

(Also note that I changed the loop counter type from int to vector<string>::size_type.)

2 Comments

Impressive! I'm looking forward to C++0x's new facilities.
@Kensai: Note that the implementation of any_of is almost trivial. In case your "impressive" comment is referring to bind2nd and equal_to, that's good old C++98.
1

While other methods including set or std::find are actually very good and fast,
you should be able to understand how to make it by yourself.
If you want to check all elements in words against all elements in disliked you actually need another for loop.

 for (std::size_t i = 0; i < words.size(); ++i) { bool found = false; for (std::size_t j = 0; j < disliked.size(); ++j) { if (words[i] == disliked[j]) { found = true; break; } if (not found) cout << words[i] << " "; else cout << "BLEEP" << " "; } 

This is basically the code you will call using std::find. Note that the find method of std::set use a different approach often implemented using red-black tree which is much more efficient.

Comments

0

You basically want to check are the all elements the same. The best idea is to use set. If you need vector for something else the fastest way is to sort the vector, go through it and check if any subsequent elements are same (O(n log(n) + n)). If your vectors aren't big the answer with 2 for loops will do the job (O(n^2)).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.