For example, I would need {20,6,143} to become {"20","6","143"}.
Simply using a range-based for-loop you could iterate through the vector of integers and using std::to_string you could convert each element to string and store to the new vector of strings.
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<int> vec{ 20,6,143 };
std::vector<std::string> strVec;
strVec.reserve(vec.size()); // reserve memory for unwanted reallocations
for (int element : vec)
strVec.emplace_back(std::to_string(element));
for (const auto& str : strVec)
std::cout << str << " ";
}
(See live online)
Alternatively using std::transform, you could transform the vector of integers as follows.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // std::transform
#include <iterator> // std::cbegin
int main()
{
std::vector<int> vec{ 20,6,143 };
std::vector<std::string> strVec;
strVec.reserve(vec.size()); // reserve memory for unwanted reallocations
std::transform(std::cbegin(vec), std::cend(vec),
std::back_inserter(strVec), // insert to the back of strVec
[](const int element) { return std::to_string(element);}
);
for (const auto& str : strVec)
std::cout << str << " ";
}
(See live online)
std::transform combined with std::to_string should do the trick.
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.
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.
I am wondering how to resolve this problem where the vectors (vec, vec2) are destroyed after exiting storeData(), which causes a segmentation fault in main().
Should I allocate memories for each vector (vec, vec2)? If so, which is the best way to do it?
Also, how could I delete them after?
Thank you.
#include <map>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void storeData();
multimap<int, vector<string> > mypairs;
void storeData()
{
vector<string> vec;
vec.push_back("one");
vec.push_back("two");
vector<string> vec2;
vec2.push_back("alpha");
vec2.push_back("beta");
mypairs.insert(make_pair(1, vec));
mypairs.insert(make_pair(2, vec2));
}
int main(int, char**)
{
storeData();
string str;
vector<string>::const_iterator it;
multimap<int, vector<string> >::const_iterator res;
res = mypairs.find(1);
for(it = res->second.begin(); it < res->second.end(); it++) {
str = *it;
}
//use string str to do something else later...
}
vec and vec2 will be copied into mypairs, so it doesn't matter if the original objects are destroyed.
You should post more information about the segfault.
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 "