It's amazing that std::set be converted to MySet, but how to avoid ?
#include <bits/stdc++.h>
struct MySet : public std::set<int> {
MySet(const std::set<int>& s) {
}
};
std::set<int> get(int i) {
return std::set<int>{i};
}
int main() {
const MySet& a = get(0);
std::cout << a.empty() << std::endl; // true
}
const MySet& a = get(0); should give compile error.
const MySet& a = get(0); should compile error
This can be done either by removing the converting ctor MySet::MySet(const std::set<int>&)or by making it explicit as shown below:
struct MySet : public std::set<int> {
//vvvvvvvv---------------------------------->make this ctor explicit
explicit MySet(const std::set<int>& s) {
}
};
int main() {
const MySet& a = get(0);
std::cout << a.empty() << std::endl; // gives error now
}
Is there a standard algorithm that I can use to subset a vector of structs by a vector of pointers to these structs?
E.g.
typedef struct {
int a;
char b;
} some_struct_t;
int main()
{
std::vector<some_struct_t> v = { {10, '1'}, { 5, '2'} };
std::vector<some_struct_t*> v2;
std::some_subset_command<some_struct_t, some_struct_t*>(begin(v), end(v), std::back_inserter(v2), [](const somestruct&) { if (somestruct.a == 5) { return &somestruct; }});
}
some_subset_command() should construct the new vector using the back_inserter and the output from the lambda predicate.
How can I do this in the most declarative way?
If you don't mind changing your std::vector<some_struct_t*> v2 to a std::vector<std::reference_wrapper<some_struct_t>> v2 (include <functional>), you could use std::copy_if:
#include <vector>
#include <algorithm>
#include <functional>
typedef struct {
int a;
char b;
} some_struct_t;
int main()
{
std::vector<some_struct_t> v = { {10, '1'}, { 5, '2'} };
std::vector<std::reference_wrapper<some_struct_t>> v2;
std::copy_if(begin(v), end(v), std::back_inserter(v2), [](const auto &s) {
return s.a == 5;
});
}
More information for std::reference_wrapper at cppreference.
If your compiler supports C++20, then you can use range adaptors:
#include <ranges>
#include <vector>
typedef struct {
int a;
char b;
} some_struct_t;
int main()
{
std::vector<some_struct_t> v = { {10, '1'}, { 5, '2'} };
auto r = v | std::views::filter([](auto& somestruct) { return somestruct.a == 5; })
| std::views::transform([](auto& somestruct) { return &somestruct; });
std::vector<some_struct_t*> v2(r.begin(), r.end());
}
Demo.
How to implement an iterator of just on values of a map/unordered_map using boost::iterator_adaptor? I've tried following code but it does not work because of the line with comment.
Is there a solution to avoid the problem?
The question here is slightly different from map_values adapter example shown in boost code as here the value field in map is another container like list or vector and the requirement here is to iterate over all elements of those lists for every key of the map.
The deref of iterator is of type of value_type of those list/vector.The end of iterator is the end of list of last key
#include <vector>
#include <boost/unordered_map.hpp>
#include <cassert>
#include <iostream>
#include <boost/iterator/iterator_adaptor.hpp>
class DS {
public:
DS() : _map() {}
~DS() {
for (Map::iterator it = _map.begin(); it != _map.end(); ++it) {
delete (it->second);
}
}
void add(int key_, const std::vector< int > &value_)
{
IntList *ptr = new IntList(value_);
assert(ptr);
_map.insert(Map::value_type(key_, ptr));
}
private:
typedef std::vector< int > IntList;
typedef boost::unordered_map< int, IntList* > Map;
Map _map;
public:
class KeyIter : public boost::iterator_adaptor< KeyIter,
Map::const_iterator,
int,
boost::forward_traversal_tag,
int>
{
public:
KeyIter() : KeyIter::iterator_adaptor_() {}
private:
friend class DS;
friend class boost::iterator_core_access;
explicit KeyIter(Map::const_iterator it) : KeyIter::iterator_adaptor_(it) {}
explicit KeyIter(Map::iterator it) : KeyIter::iterator_adaptor_(it) {}
int dereference() const { return this->base()->first; }
};
class ValueIter : public boost::iterator_adaptor< ValueIter,
Map::const_iterator,
int,
boost::forward_traversal_tag,
int>
{
public:
ValueIter()
: ValueIter::iterator_adaptor_()
, _lIt()
{}
private:
friend class DS;
friend class boost::iterator_core_access;
explicit ValueIter(Map::const_iterator it)
: ValueIter::iterator_adaptor_(it)
, _lIt()
, _mIt(it)
{
IntList *pt = it->second; // <<-- issue here is I can't find if I've already reached the end of the map
if (pt) {
_lIt = it->second->begin();
}
}
int dereference() const { return *_lIt; }
void increment()
{
if (_lIt == _mIt->second->end()) {
++_mIt;
_lIt = _mIt->second->begin();
} else {
++_lIt;
}
}
IntList::iterator _lIt;
Map::const_iterator _mIt;
};
KeyIter beginKey() const { return KeyIter(_map.begin()); }
KeyIter endKey() const { return KeyIter(_map.end()); }
ValueIter beginValue() const { return ValueIter(_map.begin()); }
ValueIter endValue() const { return ValueIter(_map.end()); }
};
int main(int argc, char** argv)
{
DS ds;
std::vector< int > v1;
v1.push_back(10);
v1.push_back(30);
v1.push_back(50);
ds.add(90, v1);
std::vector< int > v2;
v2.push_back(20);
v2.push_back(40);
v2.push_back(60);
ds.add(120, v2);
std::cout << "------------ keys ---------------" << std::endl;
for (DS::KeyIter it = ds.beginKey(); it != ds.endKey(); ++it) {
std::cout << (*it) << std::endl;
}
std::cout << "------------ values ---------------" << std::endl;
// std::cout << (*(ds.beginValue())) << std::endl;
for (DS::ValueIter it = ds.beginValue(); it != ds.endValue(); ++it) {
std::cout << (*it) << std::endl;
}
return 0;
}
Implemented in c++11. You should be able to do the conversion to boost/c++03 fairly simply.
This iterator is FORWARD ONLY and it's quite fragile (see the comparison operator).
user discretion advised.
#include <iostream>
#include <vector>
#include <unordered_map>
typedef std::vector< int > IntList;
typedef std::unordered_map< int, IntList* > Map;
struct whole_map_const_iterator
{
using C1 = IntList;
using C2 = Map;
using I1 = C1::const_iterator;
using I2 = C2::const_iterator;
using value_type = I1::value_type;
using reference = I1::reference;
whole_map_const_iterator(I2 i2) : _i2(i2) {}
bool operator==(const whole_map_const_iterator& r) const {
if (_i2 != r._i2)
return false;
if (deferred_i1 && r.deferred_i1)
return true;
if (deferred_i1 != r.deferred_i1)
return false;
return _i1 == r._i1;
}
bool operator!=(const whole_map_const_iterator& r) const { return !(*this == r); }
reference operator*() const {
check_deferred();
return *_i1;
}
void check_deferred() const {
if (deferred_i1) {
_i1 = _i2->second->begin();
_i1limit = _i2->second->end();
deferred_i1 = false;
}
}
void go_next()
{
check_deferred();
if (++_i1 == _i1limit) {
++_i2;
deferred_i1 = true;
}
}
whole_map_const_iterator& operator++() {
go_next();
return *this;
}
whole_map_const_iterator operator++(int) {
auto result = *this;
go_next();
return result;
}
I2 _i2;
mutable I1 _i1 = {}, _i1limit = {};
mutable bool deferred_i1 = true;
};
IntList a { 1, 2, 3, 4, 5 };
IntList b { 6, 7, 8, 9, 10 };
Map m { { 1, &a }, { 2, &b } };
int main()
{
using namespace std;
auto from = whole_map_const_iterator(m.begin());
auto to = whole_map_const_iterator(m.end());
for ( ; from != to ; ++from) {
std::cout << *from << std::endl;
}
return 0;
}
example output:
6
7
8
9
10
1
2
3
4
5
For bonus points, answer this question:
Q: Why all that damn complication over the deferred flag?
I want to find intersection between two maps. My map has structure map<int,line>, where line is a structure. The problem is when i use set_intersection for performing the intersection i get the following error represented in the image.
Below is my code
#include <string>
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
typedef pair<int, int> point;
struct line
{
int lineid;
point starting, ending;
};
int main(int argc, char* argv[])
{
typedef map<int, line> mymap;
line w,x,y,z;
w.lineid = 1;
w.starting = { 5, 1 };
w.ending = { 5, 100 };
x.lineid = 2;
x.starting = { 20, 56 };
x.ending = { 120, 56 };
y.lineid = 3;
y.starting = { 100, 150 };
y.ending = { 100, 200 };
z.lineid = 4;
z.starting = { 330, 50 };
z.ending = { 330, 150 };
mymap bin1;
bin1.insert({ w.lineid, w });
bin1.insert({ x.lineid, x });
bin1.insert({ y.lineid, y });
mymap bin2;
bin2.insert({ x.lineid, x });
bin2.insert({ y.lineid, y });
bin2.insert({ z.lineid, z });
mymap out;
mymap::iterator out_itr(out.begin());
set_intersection(bin1.begin(), bin1.end(), bin2.begin(), bin2.end(),
inserter(out, out_itr));
cout << "" << out.size();
return 0;
}
Any help to solve this issue will be helpful.
The compiler is complaining for not finding an operator< to compare lines object (you need to compare std::pair<int, line>, and the comparator for it needs to compare lines).
You must provide a comparator for your lines :
Example :
bool operator<(const line& other) const
{
return other.lineid < lineid; // Or whatever logic you want to compare your lines.
}
Live example here
Note :
Alternatively, you can directly provide a comparator to set_intersection, e.g. here with a lambda :
set_intersection(bin1.begin(),
bin1.end(),
bin2.begin(),
bin2.end(),
inserter(out, out_itr),
[] (const std::pair<int, line>& p1, const std::pair<int, line>& p2) { return p1.first != p2.first; } );
Are there any C++ transformations which are similar to itertools.groupby()?
Of course I could easily write my own, but I'd prefer to leverage the idiomatic behavior or compose one from the features provided by the STL or boost.
#include <cstdlib>
#include <map>
#include <algorithm>
#include <string>
#include <vector>
struct foo
{
int x;
std::string y;
float z;
};
bool lt_by_x(const foo &a, const foo &b)
{
return a.x < b.x;
}
void list_by_x(const std::vector<foo> &foos, std::map<int, std::vector<foo> > &foos_by_x)
{
/* ideas..? */
}
int main(int argc, const char *argv[])
{
std::vector<foo> foos;
std::map<int, std::vector<foo> > foos_by_x;
std::vector<foo> sorted_foos;
std::sort(foos.begin(), foos.end(), lt_by_x);
list_by_x(sorted_foos, foos_by_x);
return EXIT_SUCCESS;
}
This doesn't really answer your question, but for the fun of it, I implemented a group_by iterator. Maybe someone will find it useful:
#include <assert.h>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using std::cout;
using std::cerr;
using std::multiset;
using std::ostringstream;
using std::pair;
using std::vector;
struct Foo
{
int x;
std::string y;
float z;
};
struct FooX {
typedef int value_type;
value_type operator()(const Foo &f) const { return f.x; }
};
template <typename Iterator,typename KeyFunc>
struct GroupBy {
typedef typename KeyFunc::value_type KeyValue;
struct Range {
Range(Iterator begin,Iterator end)
: iter_pair(begin,end)
{
}
Iterator begin() const { return iter_pair.first; }
Iterator end() const { return iter_pair.second; }
private:
pair<Iterator,Iterator> iter_pair;
};
struct Group {
KeyValue value;
Range range;
Group(KeyValue value,Range range)
: value(value), range(range)
{
}
};
struct GroupIterator {
typedef Group value_type;
GroupIterator(Iterator iter,Iterator end,KeyFunc key_func)
: range_begin(iter), range_end(iter), end(end), key_func(key_func)
{
advance_range_end();
}
bool operator==(const GroupIterator &that) const
{
return range_begin==that.range_begin;
}
bool operator!=(const GroupIterator &that) const
{
return !(*this==that);
}
GroupIterator operator++()
{
range_begin = range_end;
advance_range_end();
return *this;
}
value_type operator*() const
{
return value_type(key_func(*range_begin),Range(range_begin,range_end));
}
private:
void advance_range_end()
{
if (range_end!=end) {
typename KeyFunc::value_type value = key_func(*range_end++);
while (range_end!=end && key_func(*range_end)==value) {
++range_end;
}
}
}
Iterator range_begin;
Iterator range_end;
Iterator end;
KeyFunc key_func;
};
GroupBy(Iterator begin_iter,Iterator end_iter,KeyFunc key_func)
: begin_iter(begin_iter),
end_iter(end_iter),
key_func(key_func)
{
}
GroupIterator begin() { return GroupIterator(begin_iter,end_iter,key_func); }
GroupIterator end() { return GroupIterator(end_iter,end_iter,key_func); }
private:
Iterator begin_iter;
Iterator end_iter;
KeyFunc key_func;
};
template <typename Iterator,typename KeyFunc>
inline GroupBy<Iterator,KeyFunc>
group_by(
Iterator begin,
Iterator end,
const KeyFunc &key_func = KeyFunc()
)
{
return GroupBy<Iterator,KeyFunc>(begin,end,key_func);
}
static void test()
{
vector<Foo> foos;
foos.push_back({5,"bill",2.1});
foos.push_back({5,"rick",3.7});
foos.push_back({3,"tom",2.5});
foos.push_back({7,"joe",3.4});
foos.push_back({5,"bob",7.2});
ostringstream out;
for (auto group : group_by(foos.begin(),foos.end(),FooX())) {
out << group.value << ":";
for (auto elem : group.range) {
out << " " << elem.y;
}
out << "\n";
}
assert(out.str()==
"5: bill rick\n"
"3: tom\n"
"7: joe\n"
"5: bob\n"
);
}
int main(int argc,char **argv)
{
test();
return 0;
}
Eric Niebler's ranges library provides a group_by view.
according to the docs it is a header only library and can be included easily.
It's supposed to go into the standard C++ space, but can be used with a recent C++11 compiler.
minimal working example:
#include <map>
#include <vector>
#include <range/v3/all.hpp>
using namespace std;
using namespace ranges;
int main(int argc, char **argv) {
vector<int> l { 0,1,2,3,6,5,4,7,8,9 };
ranges::v3::sort(l);
auto x = l | view::group_by([](int x, int y) { return x / 5 == y / 5; });
map<int, vector<int>> res;
auto i = x.begin();
auto e = x.end();
for (;i != e; ++i) {
auto first = *((*i).begin());
res[first / 5] = to_vector(*i);
}
// res = { 0 : [0,1,2,3,4], 1: [5,6,7,8,9] }
}
(I compiled this with clang 3.9.0. and --std=c++11)
I recently discovered cppitertools.
It fulfills this need exactly as described.
https://github.com/ryanhaining/cppitertools#groupby
What is the point of bloating standard C++ library with an algorithm that is one line of code?
for (const auto & foo : foos) foos_by_x[foo.x].push_back(foo);
Also, take a look at std::multimap, it might be just what you need.
UPDATE:
The one-liner I have provided is not well-optimized for the case when your vector is already sorted. A number of map lookups can be reduced if we remember the iterator of previously inserted object, so it the "key" of the next object and do a lookup only when the key is changing. For example:
#include <map>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
struct foo {
int x;
std::string y;
float z;
};
class optimized_inserter {
public:
typedef std::map<int, std::vector<foo> > map_type;
optimized_inserter(map_type & map) : map(&map), it(map.end()) {}
void operator()(const foo & obj) {
typedef map_type::value_type value_type;
if (it != map->end() && last_x == obj.x) {
it->second.push_back(obj);
return;
}
last_x = obj.x;
it = map->insert(value_type(obj.x, std::vector<foo>({ obj }))).first;
}
private:
map_type *map;
map_type::iterator it;
int last_x;
};
int main()
{
std::vector<foo> foos;
std::map<int, std::vector<foo>> foos_by_x;
foos.push_back({ 1, "one", 1.0 });
foos.push_back({ 3, "third", 2.5 });
foos.push_back({ 1, "one.. but third", 1.5 });
foos.push_back({ 2, "second", 1.8 });
foos.push_back({ 1, "one.. but second", 1.5 });
std::sort(foos.begin(), foos.end(), [](const foo & lhs, const foo & rhs) {
return lhs.x < rhs.x;
});
std::for_each(foos.begin(), foos.end(), optimized_inserter(foos_by_x));
for (const auto & p : foos_by_x) {
std::cout << "--- " << p.first << "---\n";
for (auto & f : p.second) {
std::cout << '\t' << f.x << " '" << f.y << "' / " << f.z << '\n';
}
}
}
How about this?
template <typename StructType, typename FieldSelectorUnaryFn>
auto GroupBy(const std::vector<StructType>& instances, const FieldSelectorUnaryFn& fieldChooser)
{
StructType _;
using FieldType = decltype(fieldChooser(_));
std::map<FieldType, std::vector<StructType>> instancesByField;
for (auto& instance : instances)
{
instancesByField[fieldChooser(instance)].push_back(instance);
}
return instancesByField;
}
and use it like this:
auto itemsByX = GroupBy(items, [](const auto& item){ return item.x; });
I wrote a C++ library to address this problem in an elegant way. Given your struct
struct foo
{
int x;
std::string y;
float z;
};
To group by y you simply do:
std::vector<foo> dataframe;
...
auto groups = group_by(dataframe, &foo::y);
You can also group by more than one variable:
auto groups = group_by(dataframe, &foo::y, &foo::x);
And then iterate through the groups normally:
for(auto& [key, group]: groups)
{
// do something
}
It also has other operations such as: subset, concat, and others.
I would simply use boolinq.h, which includes all of LINQ. No documentation, but very simple to use.