0

I have a vector of pairs, as shown below. First pair values are non-sorted and second pair values are sorted (starting from zero). I might want to store data by implementing std::vector and std::pair. When I have a first pair value (non-sorted), what is the best way to find the corresponding second pair value (sorted)? What is the best way to implement that?

The other way around is intuitive: when I have a second pair value (sorted, starting from zero), I can easily find the corresponding first pair value (non-sorted).

enter image description here

Megidd
  • 7,089
  • 6
  • 65
  • 142

1 Answers1

1

As the second value is sorted, you can perform a binary search. (If it weren't sorted, you could just use std::find_if which is linear)

To perform binary search you need to use std::lower_bound which is tricky. You need to provide a functor to tell it how your vector is sorted, in this case by the second value. If it finds the value, it returns an iterator to it. If it doesn't find the value, it either returns an iterator to another value or the end iterator. The if statement checks for end iterator first as it is invalid to dereference the end iterator.

This won't work if your vector isn't sorted by the second value. You may want to assert that it is sorted first, to avoid accidents.

The functor provided to std::lower_bound only needs the key type for the second parameter (when searching, the first pair value doesn't form the key). But to assert it is sorted, both parameters must be the type stored in the vector.

std::vector<std::pair<T1, T2>> data;
T2 find_val;

// check the vector is sorted properly
assert(std::is_sorted(data.begin(), data.end(), [](const std::pair<T1, T2>& left, const std::pair<T1, T2>& right){ return left.second < right.second; }));

// attempt to find our value
auto find_it = std::lower_bound(data.begin(), data.end(), find_val, [](const std::pair<T1, T2>& left, const T2& right){ return left.second < right; });

// check it's not the end iterator and it actually points to our value
if (find_it != data.end() && find_it->second == find_val)
{
    // found it!
    auto& retrieve_val = find_it->first;
}
else
{
    // not found
}

Here is an example using std::find_if which is a linear search but doesn't care if the vector is sorted.

auto find_it = std::find_if(data.begin(), data.end(), [&find_val](const std::pair<T1, T2>& val){ return val.second == find_val; });

if (find_it != data.end())
{
    // found it!
    auto& retrieve_val = find_it->first;
}
else
{
    // not found
}
Neil Kirk
  • 21,327
  • 9
  • 53
  • 91