inserting values of vector into unordered map - c++

I am trying to insert the values present in a vector into a unordered_map. I passed the vector to another function and declare an unordered_map and an iterator to the vector. But while compiling it gives error(below). I would like to understand why does this fail. Searching online has given me a rough idea as to what might be wrong but it is not clear to me:
1. When i pass the vector without '&', a copy of the vector is sent to the function. What does this exactly mean? How does this works internally?
2. What kind of values does make_pair take? Shouldn't 'n' and '*it' just be simple numerical values that make_pair should accept?
#include<iostream>
#include<vector>
#include<unordered_map>
#include<algorithm>
using namespace std;
void readValues(vector<int>&v, int n)
{
int temp;
while(n--)
{
cin>>temp;
v.push_back(temp);
}
}
unordered_map<int, int> storeinhashmap(vector<int>v, int n)
{
vector<int>::iterator it=v.begin();
unordered_map<int,int>h;
int temp;
while(n--)
{
temp = *it;
//cout<<"iter "<<*it<<" "<<++n<<endl;
h.insert(make_pair<int,int>(n, *it));
it++;
}
return h;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n, x;
cin>>n;
vector<int>v;
readValues(v, n);
cin>>x;
unordered_map<int, int>h = storeinhashmap(v, n);
//char ans = checksumisx(h, n);
}
return 0;
}
Error -
harshit#harshit-5570:~/Desktop/geeksforgeeks$ g++ -std=c++14 key_pair.cpp
key_pair.cpp: In function ‘std::unordered_map<int, int> storeinhashmap(std::vector<int>, int)’:
key_pair.cpp:26:43: error: no matching function for call to ‘make_pair(int&, int&)’
h.insert(make_pair<int,int>(n, *it));
^
In file included from /usr/include/c++/5/bits/stl_algobase.h:64:0,
from /usr/include/c++/5/bits/char_traits.h:39,
from /usr/include/c++/5/ios:40,
from /usr/include/c++/5/ostream:38,
from /usr/include/c++/5/iostream:39,
from key_pair.cpp:1:
/usr/include/c++/5/bits/stl_pair.h:276:5: note: candidate: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
make_pair(_T1&& __x, _T2&& __y)
^
/usr/include/c++/5/bits/stl_pair.h:276:5: note: template argument deduction/substitution failed:
key_pair.cpp:26:43: note: cannot convert ‘n’ (type ‘int’) to type ‘int&&’
h.insert(make_pair<int,int>(n, *it));

What kind of values does make_pair take? Shouldn't 'n' and '*it' just be simple numerical values that make_pair should accept?
std::make_pair is declared as follows (e.g. 20.3.3 in n3337):
template <class T1, class T2>
pair<V1, V2> make_pair(T1&& x, T2&& y);
Thus if we explicitly set these template parameters like you, no type deductions occur and this function yields
pair<int, int> make_pair(int&& x, int&& y);
Then
h.insert(make_pair<int,int>(n, *it));
shows compilation error because both n and *it are lvalues, not int&&.
This error is easily removed if we rewrite this line as follows:
h.insert(make_pair<int,int>(std::move(n), std::move(*it)));
But the most simple way to avoid this error is removing explicit template parameters like this:
h.insert(make_pair(n, *it));

As you do not want to modify the vector, you can pass it as const reference argument in order to avoid useless copies:
unordered_map<int, int> storeinhashmap(const vector<int>& v, int n)
{
// Check that the number of elements to be inserted
// is less than the size of vector
if (n < 0 || n > v.size()) {
throw invalid_argument("Wrong number of vector elements to be inserted.");
}
unordered_map<int,int>h;
for (size_t i = 0; i < (size_t)n; i++) {
h.insert(make_pair(n-i, v[i]));
}
return h;
}
In addition, I understood that n is the number of elements of the vector<int> to be inserted within unordered_map<int, int>, hence I have included a previous size check.

Related

Adding a struct into a map

I'm having trouble adding a struct into a map. I don't really understand the error.
There are 2 errors:
I can't declare a map with 'struct' type
I can't use insert to 'insert' my struct into the map
What am I doing wrong?
#include <iostream>
#include <map>
int main()
{
typedef struct
{
std::string stringVar;
unsigned unsignedVar;
float floatVar;
} MyTypeDefStruct;
MyTypeDefStruct myTypeDefStruct;
myTypeDefStruct.stringVar = "myStr";
myTypeDefStruct.unsignedVar = 1000;
myTypeDefStruct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyTypeDefStruct, float> myMap;
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
return 0;
}
error:
test.cpp: In function 'int main()':
test.cpp:21:36: error: template argument for 'template<class _Tp> struct std::less' uses local type 'main()::MyTypeDefStruct'
std::map<MyTypeDefStruct, float> myMap;
^
test.cpp:21:36: error: trying to instantiate 'template<class _Tp> struct std::less'
test.cpp:21:36: error: template argument 3 is invalid
test.cpp:21:36: error: template argument for 'template<class _T1, class _T2> struct std::pair' uses local type 'const main()::MyTypeDefStruct'
test.cpp:21:36: error: trying to instantiate 'template<class _T1, class _T2> struct std::pair'
test.cpp:21:36: error: template argument 4 is invalid
test.cpp:21:43: error: invalid type in declaration before ';' token
std::map<MyTypeDefStruct, float> myMap;
^
test.cpp:23:11: error: request for member 'insert' in 'myMap', which is of non-class type 'int'
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
^
test.cpp:23:50: error: template argument for 'template<class _T1, class _T2> struct std::pair' uses local type 'main()::MyTypeDefStruct'
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
^
test.cpp:23:50: error: trying to instantiate 'template<class _T1, class _T2> struct std::pair'
There are several issues in your code:
The struct should defined outside of the function main, can't see a reason why you want to define it there in this case, and since it is local inside of main, you can't use it anywhere else!
You are using the C-style typedef struct ... StructName instead of simply using struct MyStruct.
Your struct doesn't implement the operator<, hence, since std::map is an ordered map, and it doesn't have anyway to compare two keys (here, the key is your struct), it doesn't able to insert any pair.
Your struct doesn't implement the operator== which is important to actually retrieving the value of a certain key... You should be able to check if the keys are similar.
Another small fix - using std::make_pair instead of its ctor.
Your code should look like:
#include <iostream>
#include <map>
struct MyStruct
{
std::string stringVar;
unsigned unsignedVar;
float floatVar;
friend bool operator<(const MyStruct& l, const MyStruct& r)
{
return std::tie(l.stringVar, l.unsignedVar, l.floatVar)
< std::tie(r.stringVar, r.unsignedVar, r.floatVar);
}
friend bool operator==(const MyStruct& l, const MyStruct& r)
{
return std::tie(l.stringVar, l.unsignedVar, l.floatVar)
== std::tie(r.stringVar, r.unsignedVar, r.floatVar);
}
};
int main()
{
MyStruct my_struct;
my_struct.stringVar = "myStr";
my_struct.unsignedVar = 1000;
my_struct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyStruct, float> myMap;
myMap.insert(std::make_pair(my_struct, anotherFloat));
return 0;
}
How did I get to identifying the first problem? In the first error (always look at the first error, the others may be misleading!), it is written:
test.cpp:21:36: error: template argument for 'template<class _Tp> struct std::less' uses local type 'main()::MyTypeDefStruct'
std::map<MyTypeDefStruct, float> myMap;
Notice that the template initialization here is using main()::MyTypeDefStruct and not MyTypeDefStruct!!! These types are different, and the first is available only in the scope of main()!
The third point is because when you fix the first point, you will get:
error: no match for 'operator<' (operand types are 'const MyStruct' and 'const MyStruct')
The first problem is that map requires a way to compare two myTypeDefStructs.
You'll need to do is define operator< or std::less for your class, or pass a comparison functor to the map.
std::map<T>::insert uses a comparator to insert your elements but there is no one defined for your struct, hence try to use something like the following
#include <iostream>
#include <map>
struct MyTypeDefStruct
{
std::string stringVar;
unsigned unsignedVar;
float floatVar;
} ;
bool operator<(const MyTypeDefStruct& lhs, const MyTypeDefStruct& rhs){
return lhs.unsignedVar < rhs.unsignedVar;
}
int main()
{
MyTypeDefStruct myTypeDefStruct;
myTypeDefStruct.stringVar = "myStr";
myTypeDefStruct.unsignedVar = 1000;
myTypeDefStruct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyTypeDefStruct, float> myMap;
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
return 0;
}
A sorted map needs a less operator (operator<) to sort the elements. You have to provide such operator or you have to set a sort function. One possible solution is to implement this operator:
#include <iostream>
#include <map>
struct MyTypeDefStruct {
std::string stringVar;
unsigned unsignedVar;
float floatVar;
};
bool operator<(const MyTypeDefStruct &lhs, const MyTypeDefStruct &rhs) {
if (lhs.stringVar < rhs.stringVar) return true;
if (lhs.stringVar > rhs.stringVar) return false;
if (lhs.unsignedVar < rhs.unsignedVar) return true;
if (lhs.unsignedVar > rhs.unsignedVar) return false;
if (lhs.floatVar < rhs.floatVar) return true;
return false;
}
int main() {
MyTypeDefStruct myTypeDefStruct;
myTypeDefStruct.stringVar = "myStr";
myTypeDefStruct.unsignedVar = 1000;
myTypeDefStruct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyTypeDefStruct, float> myMap;
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
return 0;
}

C++ trying to use max and accumulate function

I am new to C++ and this is my first program that I am trying to write. In the below code I want to simulate a price of an option and calculate its value. I am getting an error for the accumulate function.
I have already tried std::max and std::accumulate but they don't work as well.
#include <iostream>
#include <algorithm>
#include <cmath>
#include<random>
#include<numeric>
#include<vector>
using namespace std;
double mc(int S, int K, float r, float vol, int T, int sim, int N){
mt19937 rng;
normal_distribution<>ND(0,1);
ND(rng);
std::vector<double> s(sim);
double dt = T/N;
for(int i =0;i<sim;i++)
{
std::vector<double> p(N);
p[0]=S;
for(int k = 0;k<N;k++)
{
double phi = ND(rng);
p[i+1] = p[i]*(1+r*dt+vol*phi*sqrt(dt));
}
s[i] = max(p[N-1]-K,0);
}
float payoff = (accumulate(s)/sim)*exp(-r*T);
return payoff;
}
int main(){
cout << mc(100,100,0.05,0.2,1,100,100) << endl;
return 0;
}
Errors :
> test1.cpp:26:21: error: no matching function for call to 'accumulate'
> float payoff = (accumulate(s)/sim)*exp(-r*T);
> ^~~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/numeric:158:1:
> note: candidate function template not viable: requires 3 arguments,
> but 1 was provided accumulate(_InputIterator __first, _InputIterator
> __last, _Tp __init) ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/numeric:168:1:
> note: candidate function template not viable: requires 4 arguments,
> but 1 was provided accumulate(_InputIterator __first, _InputIterator
> __last, _Tp __init, _BinaryOperation __binary_op) ^ 2 errors generated.
EDIT: fixed max function. it uses 0.0 instead of 0
Reading the C++ standard library documentation on std::accumulate would solve your problem. But since you're new to the language and the STL is a bit hard to decipher for beginners, here's how to read the documentation.
template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );
std::accumulate is a generic function, so it's templated on a generic type, T. In your case, T = double. It takes two input iterators, first and last, and an initial value init, of type T = double. So, below is an example on how to accumulate a std::vector<double>.
std::vector<double> v = { 1., 2., 3. };
double result = std::accumulate(v.begin(), v.end(), 0.);
Note that vector::begin and vector::end return iterators to the beginning and end, respectively, of the container.
Replace your call to accumulate using iterators and supplying an initial value.

Error using for_each and lambda

I am trying to solve a simple Fibonacci problem using the lambda function, but I came across this error and I cant solve it.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string str;
auto N{0};
auto i{0};
cout<<"Digite o valor de N desejado: ";
getline(cin,str); //pega linha
stringstream(str) >> N;
if (N == 0){cout<<0;}
else if (N == 1){cout<<1;}
else
{
vector<int> v{0,1}; //cria vetor v
for_each(v.begin(),N,
[&](){
v.push_back(v[i]+v[i+1]);
i++;
});
i = 0;
for_each(v.begin(),N,
[&](){
cout<<v[i];
i++;
});
}
return 0;
}
And the error is the following:
quest1.cpp: In function ‘int main()’: quest1.cpp:30:4: error: no matching function for call to ‘for_each(std::vector<int>::iterator, int&, main()::<lambda()>)’ });
^ In file included from /usr/include/c++/6.3.1/algorithm:62:0,
from quest1.cpp:5: /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: candidate: template<class _IIter, class _Funct> _Funct std::for_each(_IIter,
_IIter, _Funct)
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
^~~~~~~~ /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: template argument deduction/substitution failed: quest1.cpp:30:4: note: deduced conflicting types for parameter ‘_IIter’ (‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ and ‘int’) });
^ quest1.cpp:38:5: error: no matching function for call to ‘for_each(std::vector<int>::iterator, int&, main()::<lambda()>)’
});
^ In file included from /usr/include/c++/6.3.1/algorithm:62:0,
from quest1.cpp:5: /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: candidate: template<class _IIter, class _Funct> _Funct std::for_each(_IIter,
_IIter, _Funct)
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
^~~~~~~~ /usr/include/c++/6.3.1/bits/stl_algo.h:3763:5: note: template argument deduction/substitution failed: quest1.cpp:38:5: note: deduced conflicting types for parameter ‘_IIter’ (‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ and ‘int’)
});
There's two problems in your code. One (already covered by other answers), you're passing the number of iterations as the second parameter to std::for_each, but it actually expects an end iterator. std::for_each(a, b, f) is designed to iterate from iterator a to iterator b and call f on each element in that range.
The second problem is more fundamental: if you modify the vector while iterating over it, you'll get Undefined Behaviour because any modification operation invalidates all iterators to the vector.
Looking at your code, it seems you want the first loop to a normal counting loop and not iteration over the container. The second loop could be done with for_each and a lambda:
vector<int> v{0,1};
for (int i = 0; i < N; ++i) {
v.push_back(v[i] + v[i+1]);
}
for_each(v.begin(), v.end(),
[](int element) {
cout << element;
}
);
Notice that the functor used in for_each is not nullary: the algorithm will pass the element to it.
Alternatively, the printing functionality could be implemented without lambdas:
copy(v.begin(), v.end(), ostream_iterator<int>(cout));
Or, if you prefer to keep the loop, you could just as well use a range-based for loop instead of for_each. The code will be shorter and [subjective]easier to read[/subjective]:
for (int elem : v) {
std::cout << elem;
}
std::for_each requires (as the error tries to tell you) an iterator where to start looping and an iterator where to end. You however are passing an iterator and an int, which are "conflicting types". If you want to loop over an whole vector do something like that:
std::vector<int> v{1, 2, 3};
std::for_each(v.begin(), // start at the front
v.end(), // loop over each element
[&] (int& i) {
i++;
});
If you just need to loop over a part of the vector do that
std::vector<int> v{1, 2, 3};
std::for_each(v.begin(), // start at the front
v.begin() + 2, // loop over the first two elements
[&] (int& i) {
i++;
});
You are not using the for_each function correctly. C++ does not know the signature you are using. Please refer to the documentation, e.g. for_each.
The compiler says exactly that. The second parameter of the for_each you are calling is of type int&, but the signature is for_each(InputIterator, InputIterator, Function) and not for_each(InputIterator, int&, Function), so it fails to compile.

How do you create a map of maps?

I'm trying to do the following:
.h
map<int, map<int,int> > forwardingTable;
.cpp
int
UpdateForwardingTable(int dest, int hop, int cost)
{
if(forwardingTable.at(dest) != forwardingTable.end())
forwardingTable.at(dest) = make_pair(hop, cost);
else
forwardingTable.insert(dest, make_pair(hop, cost));
}
But I get a million compiler errors, similar to:
In file included from /usr/include/c++/4.8/map:60:0,
from globals.h:25,
from rtngnode.h:2,
from rtngnode.cpp:1:
/usr/include/c++/4.8/bits/stl_tree.h:316:5: note: template<class _Val> bool std::operator!=(const std::_Rb_tree_iterator<_Tp>&, const std::_Rb_tree_const_iterator<_Val>&)
operator!=(const _Rb_tree_iterator<_Val>& __x,
^
/usr/include/c++/4.8/bits/stl_tree.h:316:5: note: template argument deduction/substitution failed:
rtngnode.cpp:205:53: note: ‘std::map<int, std::map<int, int, std::less<int> > >::mapped_type {aka std::map<int, int, std::less<int> >}’ is not derived from ‘const std::_Rb_tree_iterator<_Tp>’
if(forwardingTable.at(dest) != forwardingTable.end())
Am I doing something wrong? Is there a better container for this type of thing?
There are tow problems:
1, make_pair returns pair, not map.
2, at(dest) may throws an out_of_range exception, refer map::at
It should be:
int
UpdateForwardingTable(int dest, int hop, int cost)
{
map<int, map<int,int> >::iterator itr = forwardingTable.find(dest);
if(itr != forwardingTable.end())
{
itr->second.insert(hop, cost);
// forwardingTable.at(dest) = make_pair(hop, cost);
}
else
{
map<int, int> obj;
obj.insert(hop, const);
forwardingTable.insert(dest, obj);
// forwardingTable.insert(dest, make_pair(hop, cost));
}
}

find() problems

I've got an error while using find() function. Here is the code:
#include <iostream>
#include <map>
#define N 100000
using namespace std;
int main (int argc, char * const argv[]) {
map<int,int> m;
for (int i=0; i<N; i++) m[i]=i;
find(m.begin(), m.end(), 5);
return 0;
}
I'm getting an compiller error:
error: no match for 'operator==' in '__first. __gnu_debug::_Safe_iterator<_Iterator, _Sequence>::operator* [with _Iterator = std::_Rb_tree_iterator<std::pair<const int, int> >, _Sequence = __gnu_debug_def::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >]() == __val'
Including 'algorithm' nothing changes. Compiling in VS2008 shows similar error.
I know about m.find(), but I realy need to use find() too.
Thanks a lot for your assistance!
P.S. Actualy, the task is to compare speed of m.find(5) and find(m.begin(), m.end(), 5), so I need to make both of them work properly.
begin() and end() on all STL containers provide access to elements of those collections. Type of those elements is known as value_type of the container. For std::map<Key, Value>, its value_type is std::pair<Key, Value>. Therefore, your find function is trying to find a pair<int, int> which is equal to 5. Since there's no operator== defined to compare pair<int, int> and int, you get the error.
The correct way to do this (so long as you want to avoid member find()) is to use std::find_if:
template <class First>
struct first_equal
{
const First value;
first_equal(const First& value)
: value(value)
{
}
template <class Second>
bool operator() (const std::pair<First, Second>& pair) const
{
return pair.first == value;
}
};
...
find_if(m.begin(), m.end(), first_equal<int>(5));
You could also overload operator== for pair and int to do what you want, but it's a very hackish way (because it will affect all your code, and because such a comparison has no meaning in general).
find() requires a parameter that can be compared to *iterator. For your map, this will be pair<int,int>. You'll need to create a dummy pair, plus a comparison functor to compare the pairs.
Just use m.find(5)