64

My use case:

map<string, Car> cars;
bool exists(const string& name) {
  // somehow I should find whether my MAP has a car
  // with the name provided
  return false;
} 

Could you please suggest the best and the most elegant way to do it in C++? Thanks.

yegor256
  • 102,010
  • 123
  • 446
  • 597

11 Answers11

82
return cars.find(name) != cars.end();
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
65

Sure, use an iterator

map<string,Car>::const_iterator it = cars.find(name);
return it!=cars.end();
Tom
  • 43,810
  • 29
  • 138
  • 169
  • 5
    Since you're not mutating `cars`, it's better to get a `const_iterator`. – kennytm May 06 '10 at 14:42
  • 1
    But if `cars` isn't const, `cars.find(name)` will return an `iterator` that has to be converted to a `const_iterator` and `cars.end()` will return an `iterator` which will then be converted to a `const_iterator` when compared to `it`. Why fight it; why not just use an `iterator` ? – CB Bailey May 06 '10 at 17:24
  • 6
    Why not skip the temporary and not worry about it: `cars.find(name) != cars.end()`? – D.Shawley May 06 '10 at 20:50
  • 11
    Is there a reason why C++ doesn't have something like `cars.exists(name)`? Using find produces verbose code. – Quentin Pradet Aug 31 '12 at 09:26
  • 2
    @QuentinPratet: it doesn't need .exists(), since it has .count() which is more powerful and equally terse. (example in my answer) – foo Jun 01 '15 at 08:39
  • Since I am new to C++ anybody care to explain why we check that it is not equal to end()? basically if the answerer would like to explain his answer better? – John Demetriou Jan 13 '16 at 13:00
  • 1
    Basically if it returns its equal to the end then the iterator passed through the whole map and did not find the item? – John Demetriou Jan 13 '16 at 13:02
  • @JohnDemetriou, yes, that's why. That ".end()" actually means past-last-element; see e.g. https://stackoverflow.com/questions/15252002/what-is-the-past-the-end-iterator-in-stl-c for more explanation. – foo Sep 03 '18 at 10:04
27

You could also use

bool exists(const string& name) {
  return cars.count(name) != 0;
} 
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 14
    @Potatoswatter But makes it clear exactly what is being tested. Its purely a stylistic issue, but I tend not to rely on implicit int to bool conversions. – KeithB May 06 '10 at 15:51
  • 5
    @Potatoswatter: The explicit comparison would suppress a VC++ warning ("performance warning: forcing integer to bool") ;) – UncleBens May 06 '10 at 16:05
21

Apart from the answers with iterator-Value from find() and comparison to .end(), there is another way: map::count.

You can call map::count(key) with a specific key; it will return how many entries exist for the given key. For maps with unique keys, the result will be either 0 or 1. Since multimap exists as well with the same interface, better compare with != 0 for existence to be on the safe side.

for your example, that's

return (cars.count(name)>0);

The advantages I see are 1. shorter code, 2. benefit from whatever optimisations the library may apply internally, using its representation details.

foo
  • 1,968
  • 1
  • 23
  • 35
10

What about:

template <typename KeyType, typename Collection>
bool exists_in(Collection const& haystack, KeyType const& needle) {
    return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
}

template <typename K, typename V>
bool exists_in(std::map<K,V> const& haystack, K const& needle) {
    return haystack.find(needle) != haystack.end();
}

This makes exists_in work with any standard container via std::find and use a special version for std::map since it offers a more efficient searching alternative. You could add additional specializations as necessary (e.g., for std::set and others).

D.Shawley
  • 58,213
  • 10
  • 98
  • 113
5
bool exists(const string& name)
{
    return cars.find(name) != cars.end();
}
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
4

C++20:

return cars.contains(name);
3

std::map::find(const key_type& x );

It returns map::end if the item doesn't exist.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
1
bool exists(const std::map<std::string, Car>& cars, const std::string& name) {
  return cars.end() != cars.find(name);
}
Rudi
  • 19,366
  • 3
  • 55
  • 77
  • Why not make it even more generic by making it a template function? But it probably won't fulfill the requirement of elegance any better.. – foraidt May 06 '10 at 15:01
  • @mxp, see my solution for that (http://stackoverflow.com/questions/2781899/how-to-find-whether-an-element-exists-in-stdmap/2782084#2782084). – D.Shawley May 06 '10 at 15:04
0
#define itertype(v) typeof((v).begin())
itertype(cars) it = cars.find(name);
return it != cars.end();
Dr.Vendetta
  • 15
  • 1
  • 7
  • Why wouldn't you just use `auto` instead of this macro? `auto it = cars.find(name);` – Arya McCarthy Jun 04 '17 at 18:15
  • Welcome to SO. This answer doesn't really add anything new that isn't already covered in the (much older) existing answers. Consider removing your answer and perhaps look to respond instead to questions that do not yet have accepted answers. – Craig Scott Jun 04 '17 at 21:46
0

This does not answer the question but it might be good to know. You can know if it exists by erasing it.

bool existed = cars.erase( name );
Tono Nam
  • 34,064
  • 78
  • 298
  • 470