Am I using find wrong? - c++

I'm trying to find string tp inside an unordered_map but it's giving me problems.
unordered_map < string, int > pastPoints;
int t = 0;
void doStuff(int x, int y) {
pair < int, int > tp_ = {x, y};
string tp = int_string(tp_);
if (find(pastPoints.begin(), pastPoints.end(), tp) != pastPoints.end()) {
ans = max(ans, t - pastPoints[tp]);
}
pastPoints[tp] = t;
}
It's giving me this error:
error: no match for ‘operator==’ (operand types are ‘std::pair<conststd::basic_string<char>, int>’ and ‘const std::basic_string<char>’)
{ return *__it == _M_value; }
Am I using unordered_map::find wrong? I'm finding the key which is a string.

Yes, you're using it wrong.
Don't use std::find with maps and sets. It will check the elements one by one, while maps/sets have a faster way to search for elements.
Do this: pastPoints.find(tp).
Also using pastPoints[tp] after a successful find is wasteful, since it searches the map again. Instead, dereference the iterator returned by find.
Example:
if (auto it = pastPoints.find(tp); it != pastPoints.end())
ans = max(ans, t - *it);

Related

Can I create a set of list::iterators? Will they still point to the same node after I erase/insert other nodes from the same list?

I want to create a set of list::iterators, so that when I update other nodes in the list, my iterator still points to the same node.
int n;
string s;
cin >> n >> s;
list<char> str;
for (char c : s) {
str.push_back(c);
}
vector<set<list<char>::iterator>> locations(10);
for (auto it = str.begin(); it != str.end(); ++it) {
auto next = it;
++next;
if (next != str.end()) {
int l = *it - '0', r = *next - '0';
if ((l + 1) % 10 == r) {
locations[l].insert(it);
}
}
}
I get a compile error saying
error: no match for ‘operator<’ (operand types are ‘const std::_List_iterator’ and ‘const std::_List_iterator’)
386 | { return __x < __y; }
What am I doing wrong? Is this possible in C++? Or should I create my own node structure and store pointers to it?
PS - I am trying to solve a problem from Google Kickstart (https://codingcompetitions.withgoogle.com/kickstart/round/0000000000435914/00000000008d94f5) and the string s contains only digits from 0-9.
You'd need a custom comparator. E.g. something like this:
struct CompareIterators {
template <typename It>
bool operator()(It iter1, It iter2) const {
using Ptr = decltype(&*iter1);
return std::less<Ptr>{}(&*iter1, &*iter2);
}
};
using MySet = set<list<char>::iterator, CompareIterators>;
vector<MySet> locations(10);
The order of elements in MySet will be essentially random, unpredictable. It won't necessarily correspond to the order of nodes in the list. All it ensures is that, if you insert an iterator to the same element twice, it will only appear in the set once.

binary '==': no operator found which takes a left - hand operand of type 'std::pair<const _Kty,_Ty>'

This error is pretty common but none of the solutions I have seen worked for me.
The solutions I have seen were with other types of operands instead of pair but that shouldn't be an excuse.
What I understand in the error is that I have not defined the equal operator with pairs, but I am not comparing pairs at any moment, I am always working with the key or the value.
#include "cabezeras.h"
using namespace std;
int main()
{
string x;
ifstream inFile;
bool t2, t3;
int times2 = 0, times3 = 0;
map<char, int> mymap;
map<char, int>::iterator it;
pair<char, int> aux_pair;
inFile.open("C:/Users/victor/source/repos/AdventOfCode2018/Day2/input.txt");
if (!inFile) {
cout << "Unable to open file";
exit(1);
}
while (getline(inFile, x)) {
t2 = false, t3 = false;
mymap.clear();
for (int i = 0; i < x.length(); i++) {
it = find(mymap.begin(), mymap.end(), x[i]);
if (it == mymap.end()) {
aux_pair = make_pair(x[i], 1);
mymap.insert(aux_pair);
}
else {
it->second++;
}
}
it = mymap.begin();
int valor;
while (it != mymap.end()) {
if (valor == 2) {
t2 = true;
}
if (valor == 3) {
t3 = true;
}
it++;
}
if (t2) {
times2++;
}
if (t3) {
times3++;
}
}
inFile.close();
cout << "Val = " << times2 * times3 << endl;
}
When debbuging(it takes me to xutility file):
template<class _InIt, class _Ty> inline
_InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, false_type)
{ // find first matching _Val
for (; _First != _Last; ++_First)
if (*_First == _Val) // THIS IS THE LINE OF THE ERROR
break;
return (_First);
}
Instead of using std::find you should be using std::map::find, so replace this
it = find(mymap.begin(), mymap.end(), x[i]);
with
it = mymap.find(x[i]);
You way over-complicated your code:
for (int i = 0; i < x.length(); i++) {
it = find(mymap.begin(), mymap.end(), x[i]);
if (it == mymap.end()) {
aux_pair = make_pair(x[i], 1);
mymap.insert(aux_pair);
}
else {
it->second++;
}
}
should be instead:
for (int i = 0; i < x.length(); i++)
mymap[ x[i] ]++;
or even shorter using for range loop:
for (char c : x ) mymap[c]++;
std::map::operator[] is specially designed for cases like this and you can find it in example code of the documentation.
You still have lots of C habits, forget about them.
The map iterator has a const for its first member, that's what the error message is telling you:
auto it = mymap.find(x[i]);
or if you don't have C++11
map<const char, int>::iterator it = mymap.find(x[i]);
But don't declare all your variables at the beginning, loose this habit, declare them where you need them at the appropriate scope.
When you need another it after, use another auto, and probably worth changing the name for something more descriptive.
But as Slava said, the default initializer for map says, you can do:
for (char c : x ) ++mymap[c];
This piece of code:
it = find(mymap.begin(), mymap.end(), x[i]);
if (it == mymap.end()) {
aux_pair = make_pair(x[i], 1);
mymap.insert(aux_pair);
}
else {
it->second++;
}
Could be replaced by
auto insert_pair = mymap.insert({x[i], 0});
++*insert_pair.first->second;
The insert function returns a std::pair with an iterator as the first value and a boolean indicator as the second.
If the insertion failed, because the key x[i] already exists, the iterator in first will be an iterator to the existing element pair. If the insertion succeeded, then the first will be an iterator to the newly inserted element pair.
Since I insert the data value 0, if the insertion was successful then increasing the value will make it 1 (which is what you insert). And if it fails because the key already exist, then we increase the existing value (like you do).

Forming the maximum number out of the available numbers?

I am trying to solve the following question https://www.interviewbit.com/problems/largest-number/ : Given a list of non negative integers, arrange them such that they form the largest number.
For example:
Given [3, 30, 34, 5, 9], the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.
I have been able to solve it and implemented it, using comparison based sorting technique. That is, given two numbers X and Y, I compare two numbers XY (Y appended at the end of X) and YX (X appended at the end of Y). If XY is larger, then X should come before Y in output, else Y should come before. The following is the code:
string Solution::largestNumber(const vector<int> &A) {
// Do not write main() function.
// Do not read input, instead use the arguments to the function.
// Do not print the output, instead return values as specified
// Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
vector<string> myvec;
for (int i = 0; i < A.size(); i++)
{
string s = to_string(A[i]);
myvec.push_back(s);
}
sort(myvec.begin(),myvec.end(),mycomp());
string s = "";
auto it = myvec.begin();
while (it != myvec.end())
{
string p = *it;
s = s + p;
it++;
}
return s;
}
struct mycomp
{
inline bool operator() (const string &p1, const string &p2)
{
string s1 = p1.append(p2);
string s2 = p2.append(p1);
if (s1.compare(s2) < 0)
return false;
else
return true;
}
};
But, the problem is, I have to merge the two functions into a single one because I just have to implement the single function. I cannot define one more function since I have no control over the entire piece of code (look at the link's submission part). Therefore, my ask is, how can I use the comparator by defining it inside the function string Solution::largestNumber(const vector<int> &A). Thanks!
This is a perfect place for a lambda.
sort(myvec.begin(), myvec.end(), [](const string &p1, const string &p2) {
string s1(p1 + p2);
string s2(p2 + p1);
return s1.compare(s2) >= 0;
});
I changed your code to not call append() on the strings, since you accept them as references to const objects, and p1.append(p2) tries to modify p1, but that's not allowed on a const object. Further, avoid constructs like if(x) return true else return false; and instead just return x;
Also, this
string s = "";
auto it = myvec.begin();
while (it != myvec.end())
{
string p = *it;
s = s + p;
it++;
}
return s;
Can be condensed to:
string s;
for (auto const& e : myvec)
s += e;
return s;
(Assuming you have a c++11 compiler or later)

Reverse Iterator Arithmetic

All, I'm trying to do an O(n^2) comparison between elements in a list in reverse, so I'm using a reverse iterator.
Code follows
#include <list>
struct Element {
double a;
double b;
};
typedef std::list<Element> ElementList;
class DoStuff {
public:
DoStuff();
void removeDuplicates(ElementList & incList) const {
for(ElementList::reverse_iterator stackIter = incList.rbegin(); stackIter != incList.rend(); ++stackIter) {
bool uniqueElement = true;
for(ElementList::reverse_iterator searchIter = stackIter+1; searchIter != incList.rend() && uniqueElement; ++searchIter) {
//Check stuff and make uniqueElement = true;
}
}
}
};
int main() {
std::list<Element> fullList;
DoStuff foo;
foo.removeDuplicates(fullList);
}
I get a compile error on the searchIter creation... why...
This works, but its stupid to read:
ElementList::reverse_iterator searchIter = stackIter;
searchIter++;
for( ; searchIter != incList.rend() && uniqueElement; ++searchIter) {
}
Error below:
In file included from /usr/local/include/c++/6.1.0/bits/stl_algobase.h:67:0,
from /usr/local/include/c++/6.1.0/list:60,
from main.cpp:1:
/usr/local/include/c++/6.1.0/bits/stl_iterator.h: In instantiation of 'std::reverse_iterator<_Iterator> std::reverse_iterator<_Iterator>::operator+(std::reverse_iterator<_Iterator>::difference_type) const [with _Iterator = std::_List_iterator<Element>; std::reverse_iterator<_Iterator>::difference_type = long int]':
main.cpp:16:66: required from here
/usr/local/include/c++/6.1.0/bits/stl_iterator.h:233:41: error: no match for 'operator-' (operand types are 'const std::_List_iterator<Element>' and 'std::reverse_iterator<std::_List_iterator<Element> >::difference_type {aka long int}')
{ return reverse_iterator(current - __n); }
The syntax it + n for some iterator it and integer n requires the iterator to be a "random access iterator". List iterators do not fulfill that requirement.
To get around the "stupid to read" issue, you can use std::next:
for(ElementList::reverse_iterator searchIter = std::next(stackIter); ...
Or, with less typing:
for(auto searchIter = std::next(stackIter); ...

Finding the closest or exact key in a std::map

I need to create a lookup table which links a length to a time interval (both are of data type double). The keys increment linearly as they are inserted, so it will already be sorted (perhaps an unordered_map would be better?).
What I am looking for is a way to find a key that best matches the current length provided to get the time value, or even better find the two keys that surround the length (the given key is between them) so I can find the interpolated value between the two time values.
I also need the best performance possible as it will be called in real time.
EDIT: I would have rather the following was a comment to the first answer below, but the format is hard to read.
I tried to do the following, but it seems to return the same iterator (5.6):
std::map<double, double> map;
map.insert(std::pair<double, double>(0.123, 0.1));
map.insert(std::pair<double, double>(2.5, 0.4));
map.insert(std::pair<double, double>(5.6, 0.8));
std::map<double, double>::iterator low, high;
double pos = 3.0;
low = map.lower_bound(pos);
high = map.upper_bound(pos);
How would I get 'low' to point to the last element that is < than the key used to search?
EDIT 2:
Silly me, 'low--' will do it, providing it's not the first element.
Getting there :)
For this, you can use either std::map::lower_bound
Returns an iterator pointing to the first element that is not less than key.
or std::map::equal_range
Returns a range containing all elements with the given key in the container.
In your case, if you want the closest entry, you need to check both the returned entry and the one before and compare the differences. Something like this might work
std::map<double, double>::iterator low, prev;
double pos = 3.0;
low = map.lower_bound(pos);
if (low == map.end()) {
// nothing found, maybe use rbegin()
} else if (low == map.begin()) {
std::cout << "low=" << low->first << '\n';
} else {
prev = std::prev(low);
if ((pos - prev->first) < (low->first - pos))
std::cout << "prev=" << prev->first << '\n';
else
std::cout << "low=" << low->first << '\n';
}
"best performance possible" - given you insert elements in increasing order, you can push_back/emplace_back them into a std::vector then use std::lower_bound - you'll get better cache utilisation because the data will be packed into contiguous address space.
You could of course use lower_bound and upper_bound, which are logarithmic in runtime. And they should do what you want.
std::map<double,double>::iterator close_low;
//... your_map ...
close_low=your_map.lower_bound (current_length);
This should give you an iterator to the the first map element whose key is < current length. Do likewise with upper_bound and you have your time surrounded.
The functions std::lower_bound() and std::upper_bound() would be useful here.
lower_bound() gives the first element that is >= to the value you're looking for; upper_bound() gives the first element that is > than the value.
For instance, searching for the value 5 in the following list: {1,3,5,5,6}1 using lower_bound() returns the third element, while upper_bound() would return the fifth element.
If the two functions return the same thing x, then the value you're looking for is not present in the list.
The value just before it is x-1 and the value just after it is x.
1As pointed out by Tony D in a comment, the question asked for maps, which generally do not contain duplicate elements.
I'm keeping this example though to illustrate the two functions.
Complete generic solution (original idea taken from Olaf Dietsche's answer):
#include <map>
#include <iostream>
#include <cstdint>
template <typename T1, typename T2>
T1 findClosestKey(const std::map<T1, T2> & data, T1 key)
{
if (data.size() == 0) {
throw std::out_of_range("Received empty map.");
}
auto lower = data.lower_bound(key);
if (lower == data.end()) // If none found, return the last one.
return std::prev(lower)->first;
if (lower == data.begin())
return lower->first;
// Check which one is closest.
auto previous = std::prev(lower);
if ((key - previous->first) < (lower->first - key))
return previous->first;
return lower->first;
}
int main () {
double key = 3.3;
std::map<double, int> data = {{-10, 1000}, {0, 2000}, {10, 3000}};
std::cout << "Provided key: " << key << ", closest key: " << findClosestKey(data, key) << std::endl;
return 0;
}
#include <map>
template <typename T1, typename T2>
std::map<T1, T2>::iterator nearest_key(const std::map<T1, T2>& map, T1 key) {
auto lower_bound = map.lower_bound(key);
auto upper_bound = lower_bound; upper_bound++;
if (lower_bound == map.end()) return upper_bound;
if (upper_bound == map.end()) return lower_bound;
unsigned int dist_to_lower = std::abs((int)lower_bound->first - (int)key);
unsigned int dist_to_upper = std::abs((int)upper_bound->first - (int)key);
return (dist_to_upper < dist_to_lower) ? upper_bound : lower_bound;
}
above is wrong. should be like this
template
typename std::map<T1, T2>::const_iterator nearest_key(const std::map<T1, T2>& map, T1 key)
{
auto lower_bound = map.lower_bound(key);
if (lower_bound == map.end()) return --lower_bound;
auto upper_bound = lower_bound; upper_bound++;
if (upper_bound == map.end()) return lower_bound;
auto dist_to_lower = lower_bound->first - key;
auto dist_to_upper = upper_bound->first - key;
return (dist_to_upper < dist_to_lower) ? upper_bound : lower_bound;
}
I had to solve the same problem, however provided answers do not give me the correct answer. Here is a full example if someone wants
template <typename T>
class Key
{
public:
T x;
T y;
explicit Key(T x_, T y_): x(x_), y(y_){}
bool operator<( const Key<T> right) const{
if((x == right.x) && (y == right.y)){
return false;
}
return true;
}
T operator-( const Key<T> right) const{
return std::sqrt(std::pow(x-right.x, 2) + std::pow(y-right.y, 2));
}
};
int main(int argc, char **argv)
{
std::map<Key<double>, double> pixel_mapper;
Key<double> k1(400,5);
Key<double> k2(4,5);
Key<double> k3(4,5);
Key<double> k4(4667,5);
Key<double> k5(1000,5);
pixel_mapper.insert(std::pair<Key<double>, double>(k2, 5));
pixel_mapper.insert(std::pair<Key<double>, double>(k3, 5));
pixel_mapper.insert(std::pair<Key<double>, double>(k4, 5));
pixel_mapper.insert(std::pair<Key<double>, double>(k1, 5));
auto it = std::min_element( pixel_mapper.begin(), pixel_mapper.end(),
[&](const auto &p1, const auto &p2)
{
return std::abs(p1.first - k5) < std::abs(p2.first - k5);
});
std::cout<< it->first.x << "," << it->first.y << std::endl;
return 0;
}
Here, we can use std:min_element to get the closest in case exact key is not present