Code checking the result of std::unordered_set::find won't compile

1.3k views Asked by At

I am writing a program to determine whether all characters in a string are unique or not. I am trying to do this using an unordered_set. Here is my code:

#include <iostream>
#include <unordered_set>
#include <string>

using namespace std;

bool uniqueChars(string word) {

    unordered_set<char> set;

    for (int i = 0; i < word.length(); i++) {
        auto character = set.find(word[i]);

        // if word[i] is found in set then not all chars are unique
        if (character == word[i]) {
            return false;
        }
        //else add word[i] to set
        else {
            set.insert(word[i]);
        }
    }
    return true;
}

int main() {

    string word;
    getline(cin, word);

    bool result = uniqueChars(word);
    return 0;
}

It is giving me this error:

|15|error: no match for 'operator==' (operand types are 'std::__detail::_Node_iterator' and 'char')|

I believe that means that character is not comparable to word[i], but I'm not sure.

How do I make this work?

3

There are 3 answers

2
leslie.yao On BEST ANSWER

Note that std::unordered_set::find returns an iterator, not the element. It can't be compared to the element directly.

You could check whether the element was found or not by comparing the iterator with std::unordered_set::end. e.g.

auto character = set.find(word[i]);

// if word[i] is found in set then not all chars are unique
if (character != set.end()) {
    return false;
}
//else add word[i] to set
else {
    set.insert(word[i]);
}

BTW: Better not to use set as the name of variable, which is the name of another STL container.

8
user2736738 On
*character == word[i] 

( This is the way to access the characters but it is not needed and it should be guided by a check whether it points to the past to the last element)

The *charcater is basically referencing the already inserted charcater.

  if(character != set1.end() )
     return false; // as we are sure  that it is not unique character string

You have to dereference it. but in that case you also need to do the whether it return iterator pointing to `set::end``.

By the way there is a really a simple way to do what you are trying to do.

bool uniqueChars(string word) {

    unordered_set<char> set1;

    for (int i = 0; i < word.length(); i++) 
        auto character = set1.insert(word[i]);

    return set1.size()==word.length();
}

"set" is a key word in c++

0
Potatoswatter On

Take advantage of the return value of insert. It tells you whether a duplicate was found during insertion (in which case nothing is inserted).

bool uniqueChars(string word) {
    unordered_set<char> set;
    for ( char c : word ) {
        if ( ! set.insert( c ).second ) {
            return false; // set didn't insert c because of a duplicate.
        }
    }
    return true; // No duplicates.
}

However, this isn't as efficient as it might look. unordered_set is a heap-based hash table and its implementation is fairly heavyweight. A lightweight bit-vector works well for classifying characters.

#include <bitset>

constexpr int char_values = numeric_limits< char >::max()
                          - numeric_limits< char >::min() + 1;

bool uniqueChars(string word) {
    bitset< char_values > set;

    for ( char c : word ) {
        int value_index = c - numeric_limits< char >::min();

        if ( set[ value_index ] ) {
            return false;
        } else {
            set[ value_index ] = true;
        }
    }
    return true; // No duplicates.
}