Search code examples
c++vectormaps

Why does passing in an integer that's from a vector not work in make_pair?


For the life of me I cannot figure out why this doesn't work.

#include <iostream>
#include <vector>
#include <map>
using namespace std;

int solution(vector<int> a) {
    map<int, bool> ints;
    int b;
    for(int i = 0; i < a.size(); i++) {
        if(ints[a.at(i)]) {
            return i;
        }
        else {
            ints.insert(make_pair((a.at(i)), true));
            cout << a.at(i) << " " << ints[a.at(i)] << endl;
        }
    }
    return -1;
}

int main() {
    vector<int> a = {2, 1, 3, 5, 3, 2};
    solution(a);
    
    return 0;
}

The point is to return the location of the first duplicate, yet the make_pair is never doing its job. I don't know why but it is not working, as you can see by testing the output it is never turning ints[someint] to have a boolean value of true. Yet if I replace a.at(i) with an integer then the output is as expected. What is going on? Can you not pass a.at(i) as an argument for make_pair??


Solution

  • ints[a.at(i)]
    

    Will insert false into the map if a.at(i) doesn't already exist.

    ints.insert(make_pair((a.at(i)), true)
    

    Will fail to insert into the map if a.at(i) already exists. This means that you never set any elements of the map to true.

    There are a few options to solve this.

    insert returns a pair of an iterator and a bool indicating whether the insert was successful. You can use this to overwrite the existing value:

    auto result = ints.insert(make_pair((a.at(i)), true);
    if (!result.second)
    {
      *result.first = true;
    }
    

    It's simpler though to just use the [] operator in the first place:

    ints[a.at(i)] = true;
    

    Alternatively you can use the fact that insert never overwrites the element to do everything in a single step:

    for(int i = 0; i < a.size(); i++)
    {
      auto result = ints.insert({a[i], true});
      if (!result.second) return i;
    }
    

    As all you're ever storing in the map is true a set might be simpler:

    std::set<int> ints;
    for(int i = 0; i < a.size(); i++)
    {
      auto result = ints.insert(a[i]);
      if (!result.second) return i;
    }