Getting vectors representing subsets of a map - c++

I would like to get vectors representing each possible subset of specific length of consecutive elements of a map, per the inherent ordering, for example:
How can this be done?

You may iterate iver the map as key are ordered:
std::vector<std::array<Sample, 3u>> get_triplets(const std::map<int, Sample>& samples)
{
if (samples.size() < 3) {
return {};
}
std::vector<std::array<Sample, 3u>> res;
auto it = samples.begin();
auto it1 = std::next(it);
auto it2 = std::next(it1);
for (; it2 != samples.end(); ++it, ++it1, ++it2) {
res.push_back({{it->second, it1->second, it2->second}});
}
return res;
}
Live Demo
Edit: to have n-uplets, small changes from previous triplet version:
std::vector<std::vector<Sample>> get_n_uplets(std::size_t n, const std::map<int, Sample>& samples)
{
if (samples.size() < n) {
return {};
}
std::vector<std::vector<Sample>> res;
auto first = samples.begin();
auto last = std::next(first, n - 1);
for (; last != samples.end(); ++first, ++last) {
std::vector<Sample> inner;
for (auto it = first; it != std::next(last); ++it) {
inner.push_back(it->second);
}
res.push_back(inner);
}
return res;
}
Live Demo

Related

Efficient way to find intersection of two vectors with respect to two members of vector objects

I have two vectors holding data objects. Each data object is holding coordinates and some other data. The vectors will always be sorted (first for the x coordinates and then for the y coordinates). I'm trying to delete all objects from both vectors that have coordinates that can not be found in both of the vectors. Here's an MWE of what I'm currently doing:
#include <iostream>
#include <vector>
#include <algorithm>
struct foo{
foo()=default;
foo(int x, int y, double data):x(x),y(y),data(data){}
int x;
int y;
double data;
};
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
for(auto it1=vec1.begin(); it1!=vec1.end();){
auto cur_element=*it1;
auto intersec = std::find_if(vec2.begin(),vec2.end(),[cur_element]
(foo & comp_element)->bool{
return((cur_element.x==comp_element.x) && (cur_element.y==comp_element.y));
});
if(intersec==vec2.end()) it1=vec1.erase(it1);
else ++it1;
}
for(auto it2=vec2.begin(); it2!=vec2.end();){
auto cur_element=*it2;
auto intersec = std::find_if(vec1.begin(),vec1.end(),[cur_element]
(foo & comp_element)->bool{
return((cur_element.x==comp_element.x) && (cur_element.y==comp_element.y));
});
if(intersec==vec1.end()) it2=vec2.erase(it2);
else ++it2;
}
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}
It works and gives me the expected output.
Anyway it seems really unefficient having to loop through both of the vectors. Is there a more efficient way to achieve the same output?
EDIT: It's not enough to obtain the coordinates that are represented in both vectors. What I need is an efficient way to delete the "wrong" objects from both vectors.
Your two vectors are sorted already – perfect!
First, assuming a comparison function (with up-coming C++20, this would get the space-ship operator...):
int compare(foo const& l, foo const& r)
{
return l.x != r.x ? l.x - r.x : l.y - r.y;
}
Now you can use it in the algorithm:
auto i1 = v1.begin();
auto i2 = v2.begin();
auto end1 = i1;
auto end2 = i2;
while(i1 != v1.end() && i2 != v2.end())
{
int cmp = compare(*i1, *i2);
if(cmp < 0)
{
// skip element
++i1;
}
else if(cmp > 0)
{
++i2;
}
else
{
// matching element found, keep in both vectors...
if(i1 != end1)
*end1 = std::move(*i1);
++i1;
++end1;
if(i2 != end2)
*end2 = std::move(*i2);
++i2;
++end2;
// if you can rely on move (or fallback copy) assignment
// checking for self assignment, the following simpler
// alternative can be used instead:
//*end1++ = std::move(*i1++);
//*end2++ = std::move(*i2++);
}
}
v1.erase(end1, v1.end());
v2.erase(end2, v2.end());
Linear in both vectors...
The algorithm just moves the elements to be kept to front and finally drops all the overdue ones – similarly as would std::remove_if do...
I think this solution is linear and does what you want.
Possible further enhancement:
for large vectors with large areas of non-intersection, it may be worth caching regions to erase.
another strategy if data is cheap to move, is to conditionally build output vectors from input vectors and swap
struct foo_less
{
bool operator()(foo const&l, foo const& r) const
{
return std::tie(l.x, l.y) < std::tie(r.x, r.y);
}
};
void remove_non_matching(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
lcurrent = l.erase(lcurrent);
else if(less(*rcurrent, *lcurrent))
rcurrent = r.erase(rcurrent);
else
{
++lcurrent;
++rcurrent;
}
}
l.erase(lcurrent, l.end());
r.erase(rcurrent, r.end());
}
alternative approach will cost more memory but is theoretically more efficient:
void remove_non_matching_alt(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
auto lresult = std::vector<foo>(), rresult = std::vector<foo>();
auto sz = std::min(l.size(), r.size());
lresult.reserve(sz);
rresult.reserve(sz);
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
++lcurrent;
else if(less(*rcurrent, *lcurrent))
++rcurrent;
else
{
lresult.push_back(std::move(*lcurrent++));
rresult.push_back(std::move(*rcurrent++));
}
}
l.swap(lresult);
r.swap(rresult);
}
Similar but uses a thread_local persistent cache to avoid un-necessary memory allocations:
void remove_non_matching_alt_faster(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
// optimisation - minimise memory allocations on subsequent calls while maintaining
// thread-safety
static thread_local auto lresult = std::vector<foo>(), rresult = std::vector<foo>();
auto sz = std::min(l.size(), r.size());
lresult.reserve(sz);
rresult.reserve(sz);
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
++lcurrent;
else if(less(*rcurrent, *lcurrent))
++rcurrent;
else
{
lresult.push_back(std::move(*lcurrent++));
rresult.push_back(std::move(*rcurrent++));
}
}
l.swap(lresult);
r.swap(rresult);
// ensure destructors of discarded 'data' are called and prep for next call
lresult.clear();
rresult.clear();
}
This is my approach, in a erase–remove idiom style, iterating only once through the vectors:
#include <iostream>
#include <vector>
#include <iterator>
#include <utility>
struct foo
{
foo() = default;
foo(int x, int y, double data) : x(x), y(y), data(data) {}
int x;
int y;
double data;
};
// Maybe better as overloaded operators
int compare_foo(const foo& foo1, const foo& foo2)
{
if (foo1.x < foo2.x) return -1;
if (foo1.x > foo2.x) return +1;
if (foo1.y < foo2.y) return -1;
if (foo1.y > foo2.y) return +1;
return 0;
}
std::tuple<std::vector<foo>::iterator, std::vector<foo>::iterator>
remove_difference(std::vector<foo>& vec1, std::vector<foo>& vec2)
{
typedef std::vector<foo>::iterator iterator;
iterator it1 = vec1.begin();
size_t shift1 = 0;
iterator it2 = vec2.begin();
size_t shift2 = 0;
while (it1 != vec1.end() && it2 != vec2.end())
{
int cmp = compare_foo(*it1, *it2);
if (cmp < 0)
{
++it1;
shift1++;
}
else if (cmp > 0)
{
++it2;
shift2++;
}
else
{
std::iter_swap(it1, std::prev(it1, shift1));
++it1;
std::iter_swap(it2, std::prev(it2, shift2));
++it2;
}
}
return std::make_tuple(std::prev(it1, shift1), std::prev(it2, shift2));
}
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
auto remove_iters = remove_difference(vec1, vec2);
vec1.erase(std::get<0>(remove_iters), vec1.end());
vec2.erase(std::get<1>(remove_iters), vec2.end());
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}
Output:
vec1:
1 2
2 1
3 1
vec2:
1 2
2 1
3 1
The only thing to not is that this assumes that there are no repeated coordinates, or more specifically, that they are repeated the same number of times on both vectors, and "extra" repetitions would be removed (you could adapt the algorithm to change that if you needed, although it would make the code a bit uglier).
Maybe something like this? You choose first which vector is bigger then iterate (mainly) over the bigger one and check inside the other one.
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
std::vector<foo>::iterator it_begin;
std::vector<foo>::iterator it_end;
std::vector<foo>* main;
std::vector<foo>* other;
if( vec1.size() > vec2.size() ) {
it_begin = vec1.begin();
it_end = vec1.end();
main = &vec1;
other = &vec2;
}
else {
it_begin = vec2.begin();
it_end = vec2.end();
main = &vec2;
other = &vec1;
}
std::vector<foo> new_vec;
for( it_begin; it_begin != it_end; ++it_begin ) {
auto cur_element = *it_begin;
auto intersec = std::find_if( other->begin(),other->end(),[cur_element]
(foo & comp_element)->bool{
return( (cur_element.x==comp_element.x ) && ( cur_element.y==comp_element.y ) );
});
if( intersec != other->end() )
{
new_vec.push_back( cur_element );
}
}
vec1 = new_vec;
vec2 = new_vec;
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}

Fastest method to find map keys in a vector

I'm looking for the faster method to extract the map values filtered by vector keys.
Below the standard code:
std::unordered_map<uint32, user> map;
std::vector<uint32> to_find;
std::vector<user> results;
auto it = map.begin();
while (it != map.end())
{
if (std::find(to_find.begin(), to_find.end(), it->first) == to_find.end())
results.push_back(it->second);
it++;
}
You can use std::binary_search(), which has a time complexity of O(log n) where n is the size of the vector to_find. This could be much better than using std::find() which has a linear time complexity.
DEMO
#include <algorithm>
#include <iostream>
#include <vector>
#include <unordered_map>
using user = int;
using uint32 = unsigned long int;
int main()
{
std::unordered_map<uint32, user> myMap = {{1,2},{3,5},{2,9},{4,7}};
std::vector<uint32> to_find = {1,3};
std::vector<user> results;
if(to_find.size() == 0) // if you have to_find vec size = 0
std::for_each(myMap.cbegin(), myMap.cend(), [&results](const auto& ele)->void
{
results.emplace_back(ele.second);
});
else
{
for(const auto& it: myMap)// binary_search; if not found add the value
if(!std::binary_search(to_find.begin(), to_find.end(), it.first))
results.emplace_back(it.second);
}
for(const auto& it: results) std::cout << it << std::endl;
}
If both your containers are sorted, a linear way is to use algorithm similar to std::merge:
template <typename KEY, typename VALUE>
std::vector<VALUE>
collect_absents(const std::map<KEY, VALUE>& map, const std::vector<KEY>& present)
{
std::vector<VALUE> res;
auto mit = map.begin();
auto vit = present.begin();
while (mit != map.end() && vit != present.end())
{
if (*vit < mit->first) {
++vit;
} else if (mit->first < *vit) {
res.push_back(mit->second);
++mit;
} else { // equal
++vit;
++mit;
}
}
for (; mit != map.end(); ++mit) {
res.push_back(mit->second);
}
return res;
}
Demo

Compare two QMaps

What's the best way to compare two QMaps and remove the entries not in first map and add the entries of map two to the first one? Let's say I have a map with {1,2,3} and a map with {1,2,4} and I want to keep in first map {1,2,4}. Thanks.
Based on your example maps this:
void removeNonUniqueThenAppend(QMap<QString, QString>& map1, QMap<QString, QString> map2)
{
QMap<QString, QString>::iterator iterator = map1.begin();
while (iterator != map1.end()) {
if (!map2.contains(iterator.key())) {
iterator = map1.erase(iterator);
}
else {
map2.remove(iterator.key());
++iterator;
}
}
map1.unite(map2);
}
You may adapt the following to Qt:
template <typename K, typename V>
void my_merge(std::map<K, V>& m1, const std::map<K, V> m2)
{
auto it1 = m1.begin();
auto it2 = m2.begin();
while (it1 != m1.end() && it2 != m2.end()) {
if (*it1 < *it2) { // Only in m1
it1 = m1.erase(it1);
} else if (*it2 < *it1) { // Only in m2
m1.insert(it1, *it2); // with hint.
++it2;
} else { // In both
++it1;
++it2;
}
}
m1.erase(it1, m1.end());
m1.insert(it2, m2.end());
}
Demo
Demo with hint

Nested range-based for-loops

I have the following code using range-based for-loops (C++11):
vector<atom> protein;
...
for(atom &atom1 : protein) {
...
for(atom &atom2 : protein) {
if(&atom1 != &atom2) {
...
}
}
}
Is there a better/cleaner/faster way to write this nested loops? Isn't there a way to include the if condition in the second loop?
Similar to ronag's answer is a more generic version:
template<typename C, typename Op>
void each_unique_pair(C& container, Op fun)
{
for(auto it = container.begin(); it != container.end() - 1; ++it)
{
for(auto it2 = std::next(it); it2 != container.end(); ++it2)
{
fun(*it, *it2);
fun(*it2, *it);
}
}
}
UPDATE
template<typename C, typename O1, typename O2>
void each_value_and_pair(C& container, O1 val_fun, O2 pair_fun)
{
auto it = std::begin(container);
auto end = std::end(container);
if(it == end)
return;
for(; it != std::prev(end); ++it)
{
val_fun(*it);
for(auto it2 = std::next(it); it2 != end; ++it2)
{
pair_fun(*it2, *it);
pair_fun(*it, *it2);
}
}
}
Which is used like this:
main()
{
std::vector<char> values;
// populate values
// ....
each_value_and_pair(values,
[](char c1) { std::cout << "value: " << c1 << std::endl;},
[](char c1, char c2){std::cout << "pair: " << c1 << "-" << c2 << std::endl;});
}
Sad but true.
How about normal loops with iterators and auto keyword?
I think this might be what you are looking for:
for(auto it1 = std::begin(protein1); it1 != std::end(protein); ++it1)
{
for(auto it2 = std::next(it1); it2 != std::end(protein); ++it2)
{
auto& atom1 = *it1;
auto& atom2 = *it2;
// ...
}
}
you're method is just fine.
if you want to save the if statement you can
vector<atom> protein;
int i, j;
...
for(i = 0; i < protein.size() : i++) {
atom &atom1 = protein.at(i);
for(j = i+1; j < protein.size() ; j++) {
atom &atom2 = protein.at(j);
// Do something
// Swap the atom2 and atom1
// Do something again
}
}

How to keep track of current and previous iterator on a c++ vector?

I have one vector container and I would like to make a subtraction operation on the values of its content using the current iterator against the previous iterator, any help will be much appreciated
vector<MyClass>::iterator itPrevious = my_vec.begin();
vector<MyClass>::iterator itCurrent = itPrevious;
if (itCurrent != my_vec.end())
{
for (++itCurrent; itCurrent != my_vec.end(); ++itCurrent)
{
// do something with itPrevious and itCurrent
itPrevious = itCurrent;
}
}
std::vector's iterator is a RandomAccessIterator, so you can perform integer arithmetic on it. Thus, you don't need a separate "current" and "previous" pointer, as long as you start your iteration from begin() + 1:
vector<Foo> myVec = ...;
if(myVec.size() > 1) {
for(vector<Foo>::iterator iter = myVec.begin()+1; iter != myVec.end(); iter++) {
Foo current = *iter;
Foo previous = *(iter - 1);
Foo subtraction = current - previous;
...
}
}
Of course, you can't subtract the current and previous element if there are fewer than two elements in your vector. The size check might be redundant if you know your input vector will always have at least two elements, but I included it just to be safe.
Given you asked for a vector, you can use iterator arithmetic:
#include <vector>
#include <iostream>
int main() {
std::vector<int> v{ 1, 2, 3, 4 };
for ( auto i = v.begin(); i != v.end(); ++i ) {
if ( i != v.begin() )
*i = *i - *(i-1);
}
for ( auto i : v )
std::cout << i << std::endl;
}
if(v.size() < 2)
return;
auto curr = v.begin();
auto next = curr;
++next;
do
{
whatever(*next - *curr );
curr = next++;
} while( next != v.end() )
An alternative:
for (auto previous = v.begin(), current = previous + 1, end = v.end();
previous != end && current != end;
++previous, ++current)
{
std::cout << *current << " - " << *previous << " = " << *current - *previous << std::endl;
}
There are namely three more-or-less elegant ways to solve your problem.
Define a new functor
And use it in a for_each iteration
template<class T>
struct substractor {
substractor() : last(nullptr) {}
void operator()(T& item) const
{
if(last != nullptr)
*last -= item;
last = &item;
}
mutable T* last;
};
...
vector<int> v = {3, 2, 1};
for_each(v.begin(), v.end(), substractor<int>());
Define a new algorithm
Some kind of pair in-place transform here
template<typename It, typename Op>
void pair_transform(It begin, It end, Op op){
while(begin != end)
{
It next = std::next(begin);
if(next == end) break;
*begin = op(*begin, *next);
++begin;
}
}
...
vector<int> w = {3, 2, 1};
pair_transform(w.begin(), w.end(), std::minus<int>());
Keep it standard, use transform
IMHO the best one :) Concise, standard, nowhere else to look in order to understand this code.
vector<int> z = {3, 2, 1};
std::transform(z.begin(), z.end() - 1, z.begin() + 1, z.begin(),
std::minus<int>());