Step/Stride Iterator for use with std::minmax_element - c++

I have a 1D float array which represents a m *n (rows and columns) table of float values. My requirement is to find a min/max element for each row and column. For rows I can easily do it by using std::minmax_element by specifying a range of n elements. But for columns I need to use a stride iterator as elements are placed are not contiguous but placed at a step interval of n. Is there a standard iterator in boost/STL that can be used. The other option is to write my own version of it.
What is the best course ?

Two ways (among many) of doing it are using range-v3 (or boost::range) and boost::iterator.
With range-v3, it's immediate:
#include <iostream>
#include <range/v3/all.hpp>
using namespace ranges;
int main() {
std::vector<std::size_t> src{1, 2, 3, 4, 5, 6, 7};
const auto min_max = minmax(src | view::stride(3));
std::cout << min_max.first << " " << min_max.second << std::endl;
}
In boost::range, use boost::adaptors::strided.
#include <boost/range/adaptor/strided.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/assign.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
using namespace boost::adaptors;
using namespace boost::assign;
std::vector<int> input;
int arr[] = {1, 2, 3, 4, 5, 6, 7};
auto str = std::make_pair(&arr[0], &arr[8]) | strided(3);
std::cout << *boost::range::min_element(str) << " " << *boost::range::max_element(str) << std::endl;
}
Note the following:
A range can be defined by a pair of iterators, so I used that here although a simpler form is possible (it fits your use case of heap-allocated C-style arrays).
Unfortunately, this sub-library doesn't seem to have min-max (or at least I couldn't find it), so there are two calls, one for min, and one for max.
Given a random-access iterator, it's not very difficult to build a strided forward boost::iterator_facade:
#include <iostream>
#include <vector>
#include <iterator>
#include <cstddef>
#include <algorithm>
#include <boost/iterator/iterator_facade.hpp>
template<typename It>
class stride_iterator :
public boost::iterator_facade<
stride_iterator<It>,
typename std::iterator_traits<It>::value_type,
boost::forward_traversal_tag> {
public:
stride_iterator() = default;
stride_iterator(It it, It end_it, std::size_t stride) :
m_it{it}, m_end_it{end_it}, m_stride{stride}
{}
private:
friend class boost::iterator_core_access;
void increment() {
if(std::distance(m_it, m_end_it) < m_stride) {
m_it = m_end_it;
return;
}
std::advance(m_it, m_stride);
}
bool equal(const stride_iterator<It> &other) const {
return m_it == other.m_it;
}
typename std::iterator_traits<It>::value_type &dereference() const {
return *m_it; }
It m_it, m_end_it;
std::size_t m_stride;
};
This should be enough for std::minmax_element. (Adding a bit of logic, the decrement and advance members, and changing the tag, would make it into a random-access iterator too.)
int main() {
using vec_t = std::vector<int>;
vec_t v{1, 2, 3, 4, 5, 6, 7};
stride_iterator<vec_t::iterator> b{std::begin(v), std::end(v), 3}, e{std::end(v), std::end(v), 3};
auto min_max = std::minmax_element(b, e);
std::cout << *min_max.first << " " << *min_max.second << std::endl;
}

Related

Is there an elegant possibility to include several sets into a multimap?

I have several sets of the same type:
std::set< TDate> spieltagDatum;
I would like to include all of them into a multimap of this type:
std::multimap<TDate, int> ereignis;
Is there an elegant possibility (perhaps with a lambda related function?) to include all members of ONE set into the multimap above not using the iterator mechanism? (The multimap pairs should be enriched with the INT parameter during insert).
I can suggest instead of iterators to use simplified for loop with auto like below.
I used integer TDate just for example, also instead of 123 in my code you may put any function for filling in values of multimap.
Try it online!
#include <map>
#include <set>
int main() {
using TDate = int;
std::set<TDate> spieltagDatum = {3, 5, 7};
std::multimap<TDate, int> ereignis;
for (auto & e: spieltagDatum)
ereignis.emplace(e, 123);
}
What do you mean by "not using the iterator mechanism"? (Don't use iterators at your own peril)
As you describe, what you do is to 1) transform (by enrich) and 2) insert, so the answer is std::tranform + std::insert.
#include <algorithm> // transform
#include <cassert>
#include <map>
#include <set>
int main() {
using TDate = int;
std::set<TDate> spieltagDatum = {3, 5, 7};
std::set<TDate> ...;
std::multimap<TDate, int> ereignis;
auto enrich = [](auto e){return std::make_pair(e, 123);};
std::transform(
begin(spieltagDatum), end(spieltagDatum),
std::inserter(ereignis, end(ereignis)),
enrich
);
... // repeat for other sets if necessary
assert( ereignis.find(5) != ereignis.end() );
assert( ereignis.find(5)->second == 123 );
}
https://godbolt.org/z/zzYbKK83d
A more declarative option using libraries, based on #prehistoricpenguin answer is:
(IMO it is worth mainly in C++17, where so many of the templates parameters are not really necessary)
#include <cassert>
#include <map>
#include <set>
#include <boost/iterator/transform_iterator.hpp>
int main() {
using TDate = int;
std::set<TDate> spieltagDatum = {3, 5, 7};
auto enriched = [](auto it){
return boost::transform_iterator(it, [](auto e){return std::pair(e, 123);});
};
std::multimap ereignis(
enriched(begin(spieltagDatum)),
enriched(end (spieltagDatum))
);
assert( ereignis.find(5) != ereignis.end() );
assert( ereignis.find(5)->second == 123 );
}
https://godbolt.org/z/6ajssjjjP
One possible answer is to write a convert iterator class, then we use the iterator to constructor the multimap instance.
#include <iostream>
#include <iterator>
#include <map>
#include <set>
template <typename KeyT, typename ValT>
class ConvertIter
: public std::iterator<std::forward_iterator_tag, std::pair<KeyT, ValT>> {
using SetIter = typename std::set<KeyT>::iterator;
public:
ConvertIter(SetIter itr, ValT v = ValT{}) : _itr(itr), _val(v) {}
bool operator==(const ConvertIter& other) { return other._itr == _itr; }
bool operator!=(const ConvertIter& other) { return other._itr != _itr; }
std::pair<KeyT, ValT> operator*() const {
return {*_itr, _val};
}
ConvertIter& operator++() {
++_itr;
return *this;
}
ConvertIter& operator++(int) {
++_itr;
return *this;
}
private:
SetIter _itr;
ValT _val;
};
int main() {
using TDate = int;
std::set<TDate> spieltagDatum = {3, 5, 7};
std::multimap<TDate, int> ereignis(
ConvertIter<TDate, int>(spieltagDatum.begin(), 123),
ConvertIter<TDate, int>(spieltagDatum.end()));
for (auto [date, val] : ereignis) {
std::cout << "[" << date << "," << val << "]" << std::endl;
}
return 0;
}
Demo:
https://godbolt.org/z/cr98f15jq

How to find the indices of matching elements of sorted containers?

I'm trying to get the indices of one container where the elements match. Both containers are sorted in ascending order. Is there an algorithm or combo of algorithms that would place the indices of matching elements of sorted containers into another container?
I've coded an algorithm already, but was wondering if this has been coded before in the stl in some way that I didn't think of?
I would like the algorithm to have a running complexity comparable to the one I suggested, which I belive is O(min(m, n)).
#include <iterator>
#include <iostream>
template <typename It, typename Index_it>
void get_indices(It selected_it, It selected_it_end, It subitems_it, It subitems_it_end, Index_it indices_it)
{
auto reference_it = selected_it;
while (selected_it != selected_it_end && subitems_it != subitems_it_end) {
if (*selected_it == *subitems_it) {
*indices_it++ = std::distance(reference_it, selected_it);
++selected_it;
++subitems_it;
}
else if (*selected_it < *subitems_it) {
++selected_it;
}
else {
++subitems_it;
}
}
}
int main()
{
int items[] = { 1, 3, 6, 8, 13, 17 };
int subitems[] = { 3, 6, 17 };
int indices[std::size(subitems)] = {0};
auto selected_it = std::begin(items), it = std::begin(subitems);
auto indices_it = std::begin(indices);
get_indices(std::begin(items), std::end(items)
, std::begin(subitems), std::end(subitems)
, std::begin(indices));
for (auto i : indices) {
std::cout << i << ", ";
}
return 0;
}
We can use find_if to simplify the implementation of the function:
template<class SourceIt, class SelectIt, class IndexIt>
void get_indicies(SourceIt begin, SourceIt end, SelectIt sbegin, SelectIt send, IndexIt dest) {
auto scan = begin;
for(; sbegin != send; ++sbegin) {
auto&& key = *sbegin;
scan = std::find_if(scan, end, [&](auto&& obj) { return obj >= key; });
if(scan == end) break;
for(; scan != end && *scan == key; ++scan) {
*dest = std::distance(begin, scan);
++dest;
}
}
}
This doesn't make it that much shorter, but the code looks a little cleaner now. You're scanning until you find something as big as or equal to the key, and then you copy indicies to the destination as long as the source matches key.
maybe I misunderstodd the question. But there is a function in the algorithm library.
std::set_intersection
This does, what you want in one function. See:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
// Input values
std::vector<int> items{ 1,3,6,8,13,17 };
std::vector<int> subitems{ 3,6,17 };
// Result
std::vector<int> result;
// Do the work. One liner
std::set_intersection(items.begin(),items.end(), subitems.begin(),subitems.end(),std::back_inserter(result));
// Debug output: Show result
std::copy(result.begin(), result.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
If I misunderstood, then please tell me and I will find another solution.
EDIT:
I indeed misunderstood. You wanted the indices. Then maybe like this?
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using Iter = std::vector<int>::iterator;
int main()
{
// Input values
std::vector<int> items{ 1,3,6,8,13,17 };
std::vector<int> subitems{ 3,6,17 };
// Result
std::vector<int> indices{};
Iter it;
// Do the work.
std::for_each(subitems.begin(), subitems.end(), [&](int i) {it = find(items.begin(), items.end(), i); if (it != items.end()) indices.push_back(std::distance(items.begin(),it));});
// Debug output: Show result
std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Unfortunately a very long "one-liner".
I need to think more . . .
The answer is yes but it will come with C++20:
you can use ranges for this purpose:
first make a view with some predicate you like:
auto result = items | ranges::view::filter(predicate);
then take the iterator to the original array from base, for example result.begin().base() will give you the iterator to the begin of result in the original array.
#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
int main()
{
std::vector<int> items = { 1, 3, 6, 8, 13, 17 };
std::vector<int> subitems = { 3, 6, 17 };
auto predicate = [&](int& n){
for(auto& s : subitems)
if(n == s)
return true;
return false;
};
auto result = items | ranges::view::filter(predicate);
for (auto& n : result)
{
std::cout << n << '\n';
}
for(auto it = result.begin(); it != result.end(); ++it )
std::cout << it.base() - items.begin() << ' ';
}
see the godbolt
By using std::set_intersection, defining an assignment_iterator class and a assignment helper, this is possible:
#include <iterator>
#include <iostream>
#include <algorithm>
#include <vector>
template <typename Transform>
class assignment_iterator
{
Transform transform;
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
assignment_iterator(Transform transform)
: transform(transform)
{}
// For some reason VC++ is assigning the iterator inside of std::copy().
// Not needed for other compilers.
#ifdef _MSC_VER
assignment_iterator& operator=(assignment_iterator const& copy)
{
transform.~Transform();
new (&transform) Transform(copy.transform);
return *this;
}
#endif
template <typename T>
constexpr assignment_iterator& operator=(T& value) {
transform(value);
return *this;
}
constexpr assignment_iterator& operator* ( ) { return *this; }
constexpr assignment_iterator& operator++( ) { return *this; }
constexpr assignment_iterator& operator++(int) { return *this; }
};
template <typename Transform>
assignment_iterator<Transform> assignment(Transform&& transform)
{
return { std::forward<Transform>(transform) };
}
int main()
{
int items[] = { 1, 3, 6, 8, 13, 17 };
int subitems[] = { 3, 6, 17 };
std::vector<int> indices;
std::set_intersection(std::begin(items), std::end(items)
, std::begin(subitems), std::end(subitems)
, assignment([&items, &indices](int& item) {
return indices.push_back(&item - &*std::begin(items));
})
);
std::copy(indices.begin(), indices.end()
, assignment([&indices](int& index) {
std::cout << index;
if (&index != &std::end(indices)[-1])
std::cout << ", ";
})
);
return 0;
}
Demo
It's more code, but maybe assignment is a more generic means to do other operations, that currently require a specific implementations like back_inserter and ostream_iterator, and thus be less code in the long run (e.g. like the other use above with std::copy)?
This should work properly all the time based on the documentation here:
elements will be copied from the first range to the destination range.
You can use std::find and std::distance to find the index of the match, then put it in the container.
#include <vector>
#include <algorithm>
int main ()
{
std::vector<int> v = {1,2,3,4,5,6,7};
std::vector<int> matchIndexes;
std::vector<int>::iterator match = std::find(v.begin(), v.end(), 5);
int index = std::distance(v.begin(), match);
matchIndexes.push_back(index);
return 0;
}
To match multiple elements, you can use std::search in similar fashion.

Count elements in union of two sets using stl

I have two sets and I want to know how many elements there are at least in one set. It is a function set_union in <algorithm> which writes the union in another set, but I want only the number. Can I find it using stl without saving elements?
I agree with Marshall Clow; I don't believe there is an off-the-shelf algorithm to do this. Here's an idea I've been toying with. It is a simple class that provides a push_back method that just increments a counter. You use it with a std::back_inserter as an output iterator.
#include <initializer_list>
#include <iterator>
#include <iostream>
#include <algorithm>
template <typename T>
class CountingPushBack
{
public:
using value_type = T;
void push_back(T const &) {++count;}
std::size_t get_count() const {return count;}
private:
std::size_t count = 0;
};
int main()
{
std::initializer_list<int> il1 = { 0, 1, 2, 3, 4 };
std::initializer_list<int> il2 = { 0, 2, 4, 6, 8 };
CountingPushBack<int> cp;
std::set_union(il1.begin(), il1.end(),
il2.begin(), il2.end(),
std::back_inserter(cp));
std::cout << cp.get_count() << std::endl;
}
I don't know of such an algorithm. That being said, you can use the guts of set_union to write your own to do that; like this:
#include <iostream>
#include <set>
// Counts the number of elements that would be in the union
template <class Compare, class InputIterator1, class InputIterator2>
size_t set_union_size(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
Compare comp)
{
size_t __result = 0;
for (; first1 != last1;)
{
if (first2 == last2)
return __result + std::distance(first1, last1);
if (comp(*first2, *first1))
{
++__result;
++first2;
}
else
{
++__result;
if (!comp(*first1, *first2))
++first2;
++first1;
}
}
return __result + std::distance(first2, last2);
}
int main () {
std::set<int> s1 = { 0, 1, 2, 3, 4 };
std::set<int> s2 = { 0, 2, 4, 6, 8 };
std::cout
<< set_union_size(s1.begin(), s1.end(), s2.begin(), s2.end(), std::less<int>())
<< std::endl;
}
And this prints 7, which is what you would expect.
Although the solution by SCFrench is fine, it does require a container, while we only need a back_insert_iterator. Here is an example of an implementation.
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
template <typename T>
class count_back_inserter {
size_t &count;
public:
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
typedef std::output_iterator_tag iterator_category;
count_back_inserter(size_t &count) : count(count) {};
void operator=(const T &){ ++count; }
count_back_inserter &operator *(){ return *this; }
count_back_inserter &operator++(){ return *this; }
};
You can use it by passing a size_t variable to the constructor that will be incremented for every element that is 'added' to the 'underlying container'.
int main(){
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = { 3, 4, 5, 6, 7};
size_t count = 0;
set_union(v1.begin(), v1.end(),
v2.begin(), v2.end(),
count_back_inserter<int>(count));
std::cout << "The number of elements in the union is " << count << std::endl;
}

How can i copy first N elements of a std::map to another map?

I would like to copy first N elements of a std::map to another map. I tried copy_n but failed miserably. How can I achieve that?
#include <iostream>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
map<int,int> Map;
for ( int i=0;i<10;i++) Map[i]=i*i;
map<int,int> Map2;
std::copy_n(Map.begin(), 5, Map2.end());
return 0;
}
Use copy_n? It works as it should:
#include <algorithm>
#include <iterator>
#include <iostream>
#include <map>
int main() {
std::map<int, int> m1 { { 1, 2 }, { 2, 9 }, { 3, 6 }, { 4, 100 } }, m2;
std::copy_n(m1.begin(), 2, std::inserter(m2, m2.end()));
for (auto const & x : m2)
std::cout << x.first << " => " << x.second << "\n";
}
If you're constructing the other map from scratch, you can simply pass it the iterators that it needs to the constructor:
std::size_t n = ...;
std::map<K, V> m1 = { ... };
std::map<K, V> m2(m1.begin(), std::next(m1.begin(), n));
If you want to create a new map, you can use the range constructor. Inserting into an existing map can be done with range std::map::insert.
// copy 3 elements from map source
std::map<K,V>::iterator first = source.begin();
// can also use std::next if available
std::map<K,V>::iterator last = source.begin();
std::advance(last, 3);
std::map<K,V> m1( other.begin(), last);
m1.insert(first, last);
std::copy can also be used, but then you must use an std::inserter as output iterator.

Compare vectors and delete vectors where all elements are already inside another vector

I use a vector of vectors to store id-numbers, I would like to compare all of them and delete the elements where all values inside it are already inside another element.
Say i have 4 elements in my vector like this
[[1, 2, 3, 4], [1, 2, 3], [3], [1,2,3,5]]
In this example the second and third element should be deleted.
What would be the fastest algorithm to solve this?
Here is one possible solution.
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
typedef std::vector<int> VI;
typedef std::vector<std::vector<int>> VVI;
VVI DeleteDups(VVI vvi) {
std::map<int,int> map;
for(auto const& vi : vvi)
for(auto const& i : vi)
++map[i];
vvi.erase(
std::remove_if(begin(vvi), end(vvi),
[&map](const VI& vi)->bool {
for(int i : vi)
if(map[i] == 1) return false;
return true;
}),
end(vvi));
return vvi;
}
void Dump(const VVI& vvi) {
std::cout << "[";
for(auto const& vi : vvi) {
std::cout << "[";
for(int i : vi)
std::cout << i << ", ";
std::cout << "], ";
}
std::cout << "]\n";
}
int main () {
Dump(DeleteDups({ {1,2,3,4}, {1,2,3}, {3}, {1,2,3,5} }));
}
Here solution which fulfills "already inside another element" requirenment, not just "uniqueness" of elements.
For [[1, 2, 3, 4], [1, 2, 3], [3], [1,2,3,5]], Output is [[1, 2, 3, 4], [1,2,3,5]].
For [[1, 2, 3, 4], [1, 2, 3], [3,4], [1,2,3,5]], Output is [[1, 2, 3, 4], [1,2,3,5]].
It works as follows:
Generate map which maps values to vector of it's containers
For each vector, calculate intersections of containers of each value. If more than one item in result intersection(i.e. not only self-intersection), then such vector is removed.
#include <boost/container/vector.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>
#include <iterator>
#include <iostream>
#include <ostream>
#include <cstddef>
#include <string>
using namespace boost::assign;
using namespace boost;
using namespace std;
template<typename VecVec,typename OutputIterator>
void delete_included(const VecVec &vv,OutputIterator out)
{
typedef typename range_value<VecVec>::type vec_type;
typedef typename const vec_type *vec_id;
typedef typename range_value<vec_type>::type value_type;
unordered_map<value_type,container::vector<vec_id> > value_in;
container::vector<vec_id> all_vec_indexes;
BOOST_FOREACH(const vec_type &vec,vv)
{
all_vec_indexes.push_back(&vec);
BOOST_FOREACH(const value_type &value,vec)
{
value_in[value].push_back(&vec);
}
}
container::vector<vec_id> included_in;
container::vector<vec_id> intersect;
BOOST_FOREACH(const vec_type &vec,vv)
{
included_in=all_vec_indexes;
BOOST_FOREACH(const value_type &value,vec)
{
intersect.clear();
set_intersection(included_in,value_in[value],back_inserter(intersect));
swap(included_in,intersect);
if(included_in.size()==1)
break;
}
if(included_in.size()==1)
{
*out=vec;
++out;
}
}
}
template<typename VecVec>
void print(const VecVec &vv)
{
typedef typename range_value<VecVec>::type vec_type;
typedef typename range_value<vec_type>::type value_type;
cout << string(16,'_') << endl;
BOOST_FOREACH(const vec_type &vec,vv)
{
copy(vec,ostream_iterator<const value_type&>(cout," "));
cout << endl;
}
}
int main(int argc,char *argv[])
{
container::vector<container::vector<int> > vv
(list_of
( list_of (1)(2)(3)(4) )
( list_of (1)(2)(3) )
( list_of (3) )
( list_of (1)(2)(3)(5) )
);
print(vv);
container::vector<container::vector<int> > result;
delete_included(vv,back_inserter(result));
print(result);
return 0;
}