Let's say I have one const vector<string> with some elements in it and I'd like to create a const subset of that vector, how can I do that?
Ideally it would be cool if C++ supported something like the code below, unfortunately it doesn't. Anybody know of a work around?
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
ifstream infile("input.txt"); // contains apple, orange, banana in separate lines
istream_iterator<string> eos;
istream_iterator<string> input(infile);
const vector<string> stuff(input, eos);
const vector<string> a_stuff(stuff.copy_if([](const string& s) { return s[0] == 'a'; }));
return 0;
}
Assuming you want to make a copy that contains the subset, you can use a function and assign the result to a const vector<T>
#include <vector>
#include <algorithm>
#include <iterator>
template <typename T, typename Pred>
std::vector<T> vector_copy_if(std::vector<T> const & vec, Pred && pred)
{
std::vector<T> result;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(result), pred);
return result;
}
int main()
{
std::vector<int> const some_numbers { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> const even_numbers = vector_copy_if(some_numbers, [](int x) { return x % 2 == 0; });
}
It is also possible to use a boost::filter_iterator to achieve the same result:
#include <vector>
#include <string>
#include <boost/iterator/filter_iterator.hpp>
using namespace std;
int main()
{
const vector<string> v {"apple", "banana", "orange"};
auto filter= [] (string s){return s.length() > 0 && s[0] == 'a';};
auto start = boost::make_filter_iterator(filter, v.begin(), v.end());
auto end = boost::make_filter_iterator(filter, v.end(), v.end());
const vector<string> cv (start, end);
}
Related
I am trying to remove a tuple from a vector that matches the input string.
vector< tuple<string, int, int> > goals;
So, if the string matches with the input string x, I want it to be removed.
void remove_goal(const string& x){
goals.erase(remove(goals.begin(), goals.end(), x));
}
But I am getting this error
error: invalid operands to binary expression ('std::__1::tuple<std::__1::basic_string<char>, std::__1::basic_string<char>, int>' and 'const std::__1::basic_string<char>')
if (!(*__i == __value_))
~~~~ ^ ~~~~~~~~
Here's an example that demonstrates a fairly efficient way to delete std::tuples from a std::vector that match a criteria.
It uses the aptly named erase/remove idiom.
#include <algorithm>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
int main() {
std::vector<std::tuple<std::string, int, int>> v;
v.push_back(std::make_tuple("Hello", 1, 1));
v.push_back(std::make_tuple("Cruel", 2, 2));
v.push_back(std::make_tuple("World.\n", 3, 3));
v.erase(std::remove_if(v.begin(), v.end(),
[](auto s) { return std::get<0>(s) == "Cruel"; }),
v.end());
for (auto i : v) {
std::cout << std::get<0>(i) << ' ';
}
}
Output:
Hello World.
As you can see, you were on the right track. But you cannot directly compare a std::string to a std::tuple just because the std::tuple contains a std::string. That logic doesn't really make sense nor does it extend to other examples.
This addresses your edit where the erase occurs in a function:
#include <algorithm>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
void remove_from(std::vector<std::tuple<std::string, int, int>>& v,
const std::string& val) {
v.erase(std::remove_if(v.begin(), v.end(),
[&val](auto s) { return std::get<0>(s) == val; }),
v.end());
}
int main() {
std::vector<std::tuple<std::string, int, int>> v;
v.push_back(std::make_tuple("Hello", 1, 1));
v.push_back(std::make_tuple("Cruel", 2, 2));
v.push_back(std::make_tuple("World.\n", 3, 3));
remove_from(v, "Cruel");
for (auto i : v) {
std::cout << std::get<0>(i) << ' ';
}
}
It works because I'm just making a comparison of values held, and not attempting to modify val at all.
There is no operator== to compare a std::string and a std::tuple<std::string,int,int>. You can use std::remove_if:
#include <vector>
#include <tuple>
#include <string>
#include <algorithm>
#include <iostream>
int main(){
std::vector< std::tuple<std::string, int, int> > goals {{"foo",42,3141}};
std::string x{"foo"};
// x == goals[0]; nope !!
// goals.erase(std::remove(goals.begin(), goals.end(), x)); // nope !!
goals.erase(std::remove_if(goals.begin(),
goals.end(),
[&x](auto t){
return std::get<0>(t) == x;
}));
std::cout << goals.size();
}
Live Demo
This question already has answers here:
Sorting a vector of custom objects
(14 answers)
Closed 8 years ago.
I have a vector of string vectors. The second string in these vectors is what I'd like to sort by. Is there a way to do this using std::sort?
From what I can tell I should pass in a function within a struct/class but I'm not sure what it's supposed to really look like.
Tailor your compare function so it compares the 2nd element in string vectors.
#include <algorithm>
#include <vector>
#include <string>
using std::vector;
using std::string;
bool cmp(const vector<string> &lhs, const vector<string> &rhs)
{
return lhs[1] < rhs[1];
}
vector<vector<string> > vecvecstr;
std::sort(vecvecstr.begin(), vecvecstr.end(), cmp);
std::sort() then calls cmp() whenever a comparison for sorting is required.
If the 3rd parameter of std::sort() is omitted, it calls operator< for comparison, which compares vectors lexicographically.
This can be a solution!
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool compare(const vector<string> &V1, const vector<string> &V2) {
return V1[1] < V2[1];
}
int main(void) {
vector< vector<string> > container;
sort(container.begin(), container.end(), compare);
return 0;
}
Edit
I would like to mention an alternative way in case of you don't know that(Remember, std::sort is about 670% faster than std::qsort due to the fact of inline. So this isn't better than above) :
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int compare(const void* a, const void* b) {
vector<string> V1 = *((vector<string>*)a);
vector<string> V2 = *((vector<string>*)b);
if (V1[1] > V2[1])
return -1;
if (V1[1] == V2[1])
return 0;
return 1;
}
int main(void) {
vector< vector<string> > container;
qsort(&container[0], container.size(), sizeof(string), compare);
return 0;
}
How can I produce an output vector which filters an input vector based on whether it starts with a certain sub-string or not. I'm using c++98 and boost.
This is as far as I got:
std::string stringToFilterBy("2");
std::vector<std::string> input = boost::assign::list_of("1")("2")("22")("33")("222");
std::vector<int> output;
boost::copy( input | boost::adaptors::filtered(boost::starts_with), std::back_inserter(output) );
You can use std::remove_copy_if instead:
#include <algorithm>
#include <iterator>
#include <vector>
struct filter : public std::unary_function<std::string, bool> {
filter(const std::string &by) : by_(by) {}
bool operator()(const std::string &s) const {
return s.find(by_) == 0;
}
std::string by_;
};
std::vector<std::string> in, out;
std::remove_copy_if(in.begin(), in.end(), std::back_inserter(out),
std::not1(filter("2")));
One way is:
#include <boost/algorithm/string/predicate.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/assign.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <iterator>
#include <vector>
int main() {
std::string stringToFilterBy("2");
std::vector<std::string> input =
boost::assign::list_of("1")("2")("22")("33")("222");
std::vector<int> output;
boost::copy(
input
| boost::adaptors::filtered(
boost::bind(
boost::starts_with<std::string,std::string>, _1, stringToFilterBy))
| boost::adaptors::transformed(boost::lexical_cast<int, std::string>),
std::back_inserter(output));
}
Or without boost::bind (this way avoids naming types and avoids the need for function pointers, but requires the addition of some single-use structs):
#include <boost/algorithm/string/predicate.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/assign.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <iterator>
#include <vector>
template<typename Range1T>
struct StartsWith_T {
StartsWith_T(Range1T const& test) : test(&test) {}
template<typename Range2T>
bool operator()(Range2T const& input) const {
return boost::starts_with(input, *test);
}
Range1T const* test;
};
template<typename Range1T>
StartsWith_T<Range1T> StartsWith(Range1T const& test) {
return StartsWith_T<Range1T>(test);
}
template<typename T>
struct LexicalCaster {
typedef T result_type;
template<typename Input>
T operator()(Input const& input) const {
return boost::lexical_cast<T>(input);
}
};
int main() {
std::string stringToFilterBy("2");
std::vector<std::string> input =
boost::assign::list_of("1")("2")("22")("33")("222");
std::vector<int> output;
using namespace boost::adaptors;
boost::copy(
input
| filtered(StartsWith(stringToFilterBy))
| transformed(LexicalCaster<int>()),
std::back_inserter(output));
}
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 "
Say there is a list of integers [1,2,3,4,5] and a map function that multiplies each element with 10 and returns modified list as [10,20,30,40,50] , with out modifying the original list.
How this can be done efficiently in c++.
Here's an example:
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int multiply(int);
int main() {
vector<int> source;
for(int i = 1; i <= 5; i++) {
source.push_back(i);
}
vector<int> result;
result.resize(source.size());
transform(source.begin(), source.end(), result.begin(), multiply);
for(vector<int>::iterator it = result.begin(); it != result.end(); ++it) {
cout << *it << endl;
}
}
int multiply(int value) {
return value * 10;
}
Along the lines of #darids answer, but C++03 (current at the time of original post):
#include <vector>
#include <algorithm>
#include <functional>
std::vector<int> src;
std::vector<int> dst;
std::transform(src.begin(), src.end(),
std::back_inserter(dst),
std::bind1st(std::multiplies<int>(), 10));
If you can use it, probably the best idea is to use a function in the Standard Template Library.
For example, you might want to check out for_each or transform, which basically do just that.
I only post this to illustrate using a functor in transform rather than a global function:
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
struct MulBy : public std::unary_function<int, int>
{
MulBy(int v) : v_(v) {}
int operator()(int lhs) const
{
return lhs * v_;
}
private:
int v_;
};
int main()
{
int incoming[5] = {1, 2, 3, 4, 5};
int result[5] = {0, 0, 0, 0, 0};
transform(&incoming[0], &incoming[5], &result[0], MulBy(10));
copy(&result[0], &result[5], ostream_iterator<int>(cout, " "));
return 0;
}
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
struct MulBy : public std::unary_function<int, int>
{
MulBy(int v) : v_(v) {}
int operator()(int lhs) const
{
return lhs * v_;
}
private:
int v_;
};
int main()
{
vector<int> ListOfNumber;
ListOfNumber.push_back(1);
ListOfNumber.push_back(2);
ListOfNumber.push_back(3);
ListOfNumber.push_back(4);
ListOfNumber.push_back(5);
vector<int> ListResult;
ListResult.resize(ListOfNumber.size());
//Produces a new list
transform(ListOfNumber.begin(),ListOfNumber.end(),ListResult.begin(),MulBy(10));
copy(ListOfNumber.begin(),ListOfNumber.end(),ostream_iterator<int>(cout,"\t"));
//Modifies the original list
transform(ListOfNumber.begin(),ListOfNumber.end(),ListOfNumber.begin(),MulBy(10));
copy(ListResult.begin(),ListResult.end(),ostream_iterator<int>(cout,"\t"));
cin.get();
}
This is my implementation for an array map method, inspired directly from javascript
#include <vector>
#include <functional>
namespace wh{
namespace array{
template<typename T>
std::vector<T> map(const std::vector<T> &vectorToMap, const std::function<T(T)> &functor){
std::vector<T> ret;
for(auto &element: vectorToMap){
ret.push_back(functor(element));
}
return ret;
}
...
}
}
#include <iostream>
int main()
{
//'spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'
std::vector<std::string> words = {"spray", "limit", "elite", "exuberant", "destruction", "present", "windows", "wlol"};}
// and this is how it is used:
words = wh::array::map<std::string>(words, [](auto word){return word+"l";});
for(auto &word: words) std::cout << word << std::endl;
return 0;
}
Maybe this will be useful for someone else, still, if <algorithm> functions are a better approach, go ahead and use them.