I have a program in which I am using an iterator to get access to a value of a map entry .
#include <iostream>
#include <cstdio>
#include <unordered_map>
#include <utility>
#include <algorithm>
using namespace std;
int main()
{
int a[]={1,2,4,7,9,3,3,55,66,88,11};
int k = 58;
unordered_map<int,int> c;
int i=0;
for(auto x: a)
{
c.insert(make_pair(x,i));
i++;
}
for(auto x: c)
{
if(c.count(k-x.first)==1) printf("%d %d\n",x.second,(c.find(k-x))->second);
}
}
In the line:
if(c.count(k-x.first)==1) printf("%d %d\n",x.second,(c.find(k-x))->second);
I am getting errors especially in c.find()->second. I think it is the way to access elements from the iterator. What is wrong?
You cannot say
c.find(k-x)
Because k is an int and x is a std::pair<int, int>. Do you mean one of these two?
c.find(k - x.first)
Or
c.find(k - x.second)
As a side note, it is generally unsafe to directly derefernce the returned iterator from find because if find returns .end() (as in, it didn't find an element with that key) then you've got a problem.
Related
I am using g++ 7.1.0, yet using begin() with array as an argument throws an error. My code is
#include <iostream>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
int a[n];
for(int i = 0; i < n; i++) {
cin>>a[i];
}
sort(begin(a), end(a));
return 0;
}
It says
no matching function for call to 'begin(int [n])'
int a[n]; is invalid statement in C++. C++ doesn't allow variable length array. It is allowed only in C since C99 standard. If you need dynamic array, you should be using std::vector 99% of the time in C++.
You can do this:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main() {
std::cout<<"Enter size of array\n";
int size;
std::cin>>size;
std::vector<int> v(size);
std::cout<<"Enter "<<size<< " elements\n";
for(size_t i=0;i<v.size();++i)
std::cin>>v[i];
std::sort(v.begin(),v.end());
std::cout<<"Sorted elements are: \n";
for(const auto& i : v)
std::cout<<i<<' ';
}
See live demo here.
#include <iterator>
<algorithm> is the wrong header for begin(), end(), and, well, all the iteration functions.
Also, for the iteration functions to work, the array must be sized with a compile-time constant, so, int a[10]; works, but int a[n]; does not.
you can do this:-
#include <algorithm>
int main(){
int arr[2000];
int n = sizeof(arr)/sizeof(arr[0]);
std::sort(arr, arr+n);
}
if you are using array instead of vector then use
sort(a,a+n);
why the iteration in the code below doesn't work ? I mean the iterator is incremented but evaluating this expression o!=RateCurve.end() always give true.
i need such a function because i'm using it in a wrapper of a map to contruct an interest rate curve.
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string>
#include <map>
#include <exception>
#include <vector>
#include <stdio.h>
using namespace std;
map<double, double>::iterator getIt(map<double, double> o){
return o.begin();
}
int main ()
{
map<double, double> RateCurve;
RateCurve[3.3 ]=0.034 ;
RateCurve[1.2 ]=0.03 ;
RateCurve[0.2 ]=.001 ;
RateCurve[6.1 ]=.023 ;
map<double, double>::iterator o=getIt(RateCurve);
while (o!=RateCurve.end()){
cout << "RateCurve[" << o->first << "] = " << o->second << endl;
++o;
}
}
getIt(map<double, double> o)
You copy the map, so the iterator returned points into an entirely unrelated map to the one you wanted. Worse, the copy gets destroyed at the end of the function call, and the iterator you try to use is no longer valid, so you have Undefined Behaviour.
Make getIt take a reference, and since you don't actually change the elements, you can make it const too. Then you need to change the return type:
std::map<double, double>::const_iterator
getIt(map<double, double> const& o)
{
return o.begin();
}
Also, please reconsider your use of bad practices using namespace std; and endl.
This question already has an answer here:
invalid operator < while sorting std::list
(1 answer)
Closed 7 years ago.
#include <algorithm>
#include <bitset>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
using namespace std;
bool fun(int i, int j){
return abs(i - j) != -1;
}
int main(){
vector <int> v = { 1, 2, 3, 4, 5 };
sort(v.begin(), v.end(), fun);
for (int i = 0; i < v.size(); i++)
cout << v[i] << " ";
cout << endl;
return 0;
}
When I use the comparator 'fun' the programs throws the exception 'invalid operator <'. How can I modify this function to make the program run normally?
Your fun function does not provide strict weak ordering. If i and j are equal, it will return true. So you are not following the rules. Your implementation of the standard library responds by throwing an exception.
How can I modify this function to make the program run normally?
Assuming you want to sort in ascending order. Just use operator <.
bool fun(int i, int j)
{
return i < j;
}
Alternatively you could just use the comparator provided by the standard.
sort(v.begin(), v.end(), std::less<int>());
See the link in the comments or the answer provided by #DanielDaranas to understand why your original function doesn't work.
I am trying to copy the vector data from sample to Y as below
std::map<std::string, std::vector<double > >sample;
std::map<std::string, std::vector<double > >::iterator it1=sample.begin(), end1=sample.end();
std::vector<double> Y;
and am using the following code:
while (it1 != end1) {
std::copy(it1->second.begin(), it1->second.end(), std::ostream_iterator<double>(std::cout, " "));
++it1;
}
It prints the output ok, however when I replace the above std::copy block with the below, I get a segfault.
while (it1 != end1) {
std::copy(it1->second.begin(), it1->second.end(), Y.end());
++it1;
}
I just want to copy the contents of it1->second to Y. Why is it not working and how do I fix it?
Obviously, you want to insert objects into your vector. However, std::copy() merely takes the iterators passed and writes to them. The iterators obtained by the begin() and end() iterators don't do any insertion. What you want to use is something like this:
std::copy(it1->second.begin(), it1->second.end(), std::back_inserter(Y));
The std::back_inserter() function template is a factory function for an iterator using push_back() on its argument to append objects.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// your code goes here
vector<int> vec;
vector<int> test;
vec.push_back(1);
//test.push_back(0);
copy(vec.begin(),vec.begin()+1,test.begin());
cout << *(test.begin());
return 0;
}
output:
Runtime error time: 0 memory: 3424 signal:11
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// your code goes here
vector<int> vec;
vector<int> test;
vec.push_back(1);
test.push_back(0);
copy(vec.begin(),vec.begin()+1,test.begin());
cout << *(test.begin());
return 0;
}
output:
*Success time: 0 memory: 3428 signal:0*
1
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// your code goes here
vector<int> vec;
vector<int> test(5);
vec.push_back(1);
//test.push_back(0);
copy(vec.begin(),vec.begin()+1,test.begin());
cout << *(test.begin());
return 0;
}
Success time: 0 memory: 3428 signal:0
1
SO the reason is that you didn't initilize the vector,the vector.begin() point to somewhere restricted!
when you use a back_inserter(vector) it return a back_insert_interator that internally use a
vector.push_back rather than a *(deference) operation. So back_inserter works!
Given a multimap<A,B> M what's a neat way to create a vector<B> of all values in M with a specific key.
e.g given a multimap how can I get a vector of all strings mapped to the value 123?
An answer is easy, looping from lower->upper bound, but is there a neat loop-free method?
Here's the way to do it STL style :
// The following define is needed for select2nd with DinkumWare STL under VC++
#define _HAS_TRADITIONAL_STL 1
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <functional>
#include <map>
#include <iterator>
#include <iostream>
using namespace std;
void main()
{
typedef multimap<string, int> MapType;
MapType m;
vector<int> v;
// Test data
for(int i = 0; i < 10; ++i)
{
m.insert(make_pair("123", i * 2));
m.insert(make_pair("12", i));
}
MapType::iterator i = m.lower_bound("123");
MapType::iterator j = m.upper_bound("123");
transform(i, j, back_inserter(v), select2nd<MapType::value_type>());
copy(v.begin(), v.end(), ostream_iterator<int>(cout, ","));
}
Let's go lambda
given: multimap<A,B> M
requested: vector<B> (of all values in M with a specific key 'a'.)
method:
std::pair<M::iterator, M::iterator> aRange = M.equal_range('a')
std::vector<B> aVector;
std::transform(aRange.first, aRange.second,std::back_inserter(aVector), [](std::pair<A,B> element){return element.second;});
System environment:
compiler: gcc (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413 (with -std=c++11)
os: ubuntu 16.04
Code example:
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <functional>
#include <iostream>
int main()
{
typedef std::multimap<std::string, int> MapType;
MapType m;
std::vector<int> v;
/// Test data
for(int i = 0; i < 10; ++i)
{
m.insert(std::make_pair("123", i * 2));
m.insert(std::make_pair("12", i));
}
std::pair<MapType::iterator,MapType::iterator> aRange = m.equal_range("123");
std::transform(aRange.first, aRange.second, std::back_inserter(v), [](std::pair<std::string,int> element){return element.second;});
for(auto & elem: v)
{
std::cout << elem << std::endl;
}
return 0;
}
You need a loop anyway. All "loop-free" methods just abstract the loop away.
#include <map>
#include <vector>
#include <algorithm>
#include <ext/functional>
using namespace std;
int main () {
multimap<int, double> mm;
mm.insert(make_pair(1, 2.2));
mm.insert(make_pair(4, 2.6));
mm.insert(make_pair(1, 9.1));
mm.insert(make_pair(1, 3.1));
vector<double> v;
transform(mm.lower_bound(1), mm.upper_bound(1),
back_inserter(v), __gnu_cxx::select2nd<pair<int, double> >());
// note: select2nd is an SGI extension.
for (vector<double>::const_iterator cit = v.begin(); cit != v.end(); ++ cit)
printf("%g, ", *cit); // verify that you've got 2.2, 9.1, 3.1
return 0;
}
template <class Key, class Val>
vector<Val>& getValues(multimap<Key, Val>& multi, Key& key)
{
typedef multimap<Key, Val>::iterator imm;
static vector<Val> vect;
static struct
{
void operator()(const pair<Key, Val>& p) const
{
vect.push_back(p.second);
}
} Push;
vect.clear();
pair<imm, imm> range = multi.equal_range(key);
for_each(range.first, range.second, Push);
return vect;
}
This is a bit contrived because of your 'no loop' requirement.
I prefer:
template <class Key, class Val>
vector<Val> getValues(multimap<Key, Val>& map, Key& key)
{
vector<Val> result;
typedef multimap<Key, Val>::iterator imm;
pair<imm, imm> range = map.equal_range(key);
for (imm i = range.first; i != range.second; ++i)
result.push_back(i->second);
return result;
}
You could initialise the vector by giving it two iterators, like this:
std::multimap<std::string, std::string> bar;
...
std::vector<pair<string,string> > foo(bar.lower_bound("123"), bar.upper_bound("123"));
but that would give you a vector of pairs (ie, with both the key and value).
Another option would be to use std::copy with something like a back_inserter, which is another way to hide the loop, but with the same downside as above.
std::copy(bar.lower_bound("123"), bar.upper_bound("123"), std::back_inserter(foo));
This would append the elements (if any) to the vector foo.
For extracting the values only, I can't think of any way but to loop over the results as I'm not aware of a standard way to get only the value out of a range.
Just some addenda to the other answers hereā¦
std::mem_fn (from #include <functional>) can be used as a shorthand for the transform operator:
// previously we might've used this longhand
[](pair<int,string> element){return element.second;}
And we can use vector::resize and std::distance to allocate space for the vector in one go, rather than repeatedly resizing it with back_inserter.
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <functional>
#include <iterator>
#include <iostream>
using namespace std;
typedef multimap<int, string> MapType;
int main()
{
MapType multimap;
vector<string> valuesForKey123;
multimap.emplace(0, "red");
multimap.emplace(123, "hello");
multimap.emplace(123, "world");
multimap.emplace(0, "herring");
MapType::iterator lower{multimap.lower_bound(123)};
MapType::iterator upper{multimap.upper_bound(123)};
valuesForKey123.resize(distance(lower, upper));
transform(
lower,
upper,
valuesForKey123.begin(),
mem_fn(&MapType::value_type::second));
copy(
valuesForKey123.begin(),
valuesForKey123.end(),
ostream_iterator<string>(cout, " "));
}
// outputs "hello world "