vector< vector >: verify that all have equal sizes - c++

Is there an std/boost algorithm to verify that all vectors within a vector have the same sizes? And by extension, that a property of all elements is the same?
In the below examples, I use the hypothetical std::all_equal that I am looking for:
typedef std::vector<int> Line;
std::vector<Line> lines;
lines.push(Line(10));
lines.push(Line(11));
auto equalLengths = std::all_equal(lines.begin(), lines.end(),
[](const Line& x){ return x.size(); });
(And by extension:
std::vector<MyClass> vec;
auto equal = std::all_equal(std::begin(vec), std::end(vec),
[](const MyClass& x) { return x.property(); });
)

How about
#include <algorithm> // for std::all_of
auto const required_size = lines.front().size();
std::all_of(begin(lines), end(lines),
[required_size](const Line& x){ return x.size() == required_size; });
Won't work for empty lists, unfortunately and you have to get the required size into the predicate somehow.

I like #ComicSansMS's answer, but if you want a slightly less-clear approach that also works on empty vectors, you could use std::adjacent_find with a custom predicate:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<std::vector<int>> vv{{3, 1}, {4, 1}, {5, 9}};
bool all_same_size = std::adjacent_find(
vv.cbegin(),
vv.cend(),
[](const std::vector<int>& a, const std::vector<int>& b) {
return a.size() != b.size(); // Look for two adjacent elements that
// have different sizes
}) == vv.cend();
std::cout << "all same size: " << all_same_size << '\n';
}

Related

algorithm to combine std::unique with a reduce step?

can someone come up with a clean (and fast) solution to the following problem:
I have a sequence of entries that hold basically a key and a value, say a
struct Value {
int index = 0;
int cost = 0;
}
I now want to merge entries such that each key is only contained once but the values should be combined - i.e. each index should be only contained once in the sequence, and the cost for each duplicate index should be accumulated.
The basic solution I came up with sorts the sequence, and when equal entries are detected in the BinaryPredicate passed to std::sort, the cost will be summed into the lhs. Then the cost of rhs will be set to 0. Then follows a remove_if which removes the 0-cost values. See here for an example:
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iostream>
struct Value
{
int index = 0;
int cost = 0;
};
// generate a bunch of random values in a vector
// values will have indices in range [0..10]
std::vector<Value> generator()
{
std::vector<Value> v(20);
std::generate(v.begin(), v.end(), []() { return Value{std::rand() % 10, std::rand() % 10}; });
return v;
}
void print(const std::vector<Value> &values)
{
for (auto v : values)
std::cout << "{i=" << v.index << ", c=" << v.cost << "}, ";
std::cout << "\n";
}
//
void merge(std::vector<Value> &values)
{
// sort values and merge costs
std::sort(values.begin(), values.end(), [](auto &lhs , auto &rhs) {
if (lhs.index == rhs.index) {
lhs.cost += rhs.cost;
rhs.cost = 0;
}
return lhs.index < rhs.index;
});
// remove entries with empty cost
auto it = std::remove_if(values.begin(), values.end(), [](const auto &v) { return v.cost == 0; });
values.erase(it, values.end());
}
int main()
{
auto v = generator();
std::cout << "generated values: ";
print(v);
merge(v);
std::cout << "merged values: ";
print(v);
}
Live on Compiler Explorer
Thing is: While the example above produces the correct results, it is from what I can tell not conforming to the C++ standard. A BinaryPredicate "shall not apply any non-constant function through the dereferenced iterators" http://eel.is/c++draft/algorithms.requirements#8.sentence-4 . Compare is a BinaryPredicate. http://eel.is/c++draft/alg.sorting#general-2.sentence-1 )
Does this mean that my only option is to roll a custom inplace_unique_reduce or similar, or is there maybe an alternative elegant approach to this problem? I would prefer not having to write my own non-trivial algorithm for this.
Thanks
Assuming you are ok with additional allocations, I would use std::map (or the std::unordered_map):
auto merge_entries(std::vector<Value>& original_values) {
auto values = std::map<int, int>();
for (const auto [index, cost] : original_values) {
values[index] += cost;
}
const auto end_of_merged_values = std::transform(
values.cbegin(), values.cend(), original_values.begin(),
[](const auto entry) {
return Value{entry.first, entry.second};
}
);
original_values.erase(end_of_merged_values, original_values.end());
}
Apart from one for() loop (which can be substituted with std::for_each, although such change would introduce unnecessary boilterplate resulting in harder to read code, in my opinion), this solution uses only the STL.
We first merge all the entries using the map and then we overwrite some elements so that our original std::vector holds the merged entries. What's super convenient is the fact that std::transform returns an iterator pointing to the end of the inserted range. Why is it beneficial for us? Because apart from the unlikely scenario where no merging occurs, we have fewer elements compared to what was originally passed in. Using that iterator we can erase the rest of the vector (nonoverwritten elements) keeping it clean, STL-like style.
Assuming you are not ok with additional allocations, but you are ok with streghtening your iterator requirements (to bidirectional), I would use std::partial_sum and std::unique:
template <class BiDirIt, class BinaryPredicateCompare, class BinaryOpReduce>
auto inplace_unique_reduce(
BiDirIt first, BiDirIt last,
BinaryPredicateCompare cmp,
BinaryOpReduce reduce
) {
std::partial_sum(
std::make_reverse_iterator(last), std::make_reverse_iterator(first),
std::make_reverse_iterator(last),
[cmp, reduce](auto acc, const auto& elem) {
if (cmp(acc, elem)) {
return reduce(acc, elem);
} else {
acc = elem;
}
return acc;
}
);
return std::unique(first, last, cmp);
}
used like so:
auto values = std::vector<Value>{
{1, 1}, {2, 2}, {2, 7}, {0, 5},
{3, 3}, {1, 2}, {3, 10}
};
auto comparator = [](const auto& lhs, const auto& rhs) {
return lhs.index == rhs.index;
};
auto reducer = [](const auto& lhs, const auto& rhs) {
return Value{lhs.index, lhs.cost + rhs.cost};
};
auto to_remove = inplace_unique_reduce(
values.begin(), values.end(),
comparator,
reducer
);
values.erase(to_remove, values.end());
for (const auto[index, cost] : values) {
std::cout << index << ' ' << cost << '\n';
}
Just like your original answer, this will not merge nonadjacent elements, but to do that you either have to sort them by index or use something like map, from the first part of my answer.
The std::make_reverse_iterator calls are necessary becauase std::partial_sum accumulates the merged element in the most right-hand side one of given group of consecutive, equivalent elements. std::unique, on the other hand, preserves only the first element from such groups. Because of this, you want to merge the elements in the reverse order compared to the one you will be std::unique-ing.
You raised some concerns about situations where copying or moving is expensive - in such cases, you are either left with your custom solutions that take into considerations your unique constraints, or you ease your constraints. Here we move-assign merged entries, but that's it for the potential bottlenecks. If your move assignment operator is expensive, I fear that no standard solution will work for you and you have to roll your own, like in your answer.
This is the best I can come up with so far, but I still wonder if there is a solution that does not require a custom algorithm but instead combines existing ones:
template <class ForwardIt, class BinaryPredicateCompare, class BinaryOpReduce>
ForwardIt inplace_unique_reduce(ForwardIt first, ForwardIt last, BinaryPredicateCompare cmp, BinaryOpReduce reduce)
{
if (first == last)
return last;
ForwardIt result = first;
while (++first != last) {
if (cmp(*result, *first)) {
reduce(*result, *first);
} else if (++result != first) {
*result = std::move(*first);
}
}
return ++result;
}
Personally I would be much happier to modify the objects inside the Predicate of remove_if, since it is a much simpler and more straight-forward algorithm than sort. It does require keeping track of the output index, though:
void merge(std::vector<Value> &values)
{
std::sort(values.begin(), values.end(), [](auto &lhs , auto &rhs) { return lhs.index < rhs.index; });
std::size_t o_i = 0;
auto it = std::remove_if(values.begin(), values.end(), [&](const auto &v) {
if(o_i > 0 && values[o_i-1].index == v.index)
{
values[o_i-1].cost += v.cost;
return true;
}
o_i++;
return false; });
values.erase(it, values.end());
}
Here's another version using the range-v3 library (std::ranges doesn't have group_by yet).
#include <range/v3/all.hpp>
void merge(std::vector<Value> &values)
{
std::sort(values.begin(), values.end(), [](auto &lhs, auto &rhs) { return lhs.index < rhs.index; });
auto merged = values
| ranges::v3::view::group_by([](Value &lhs, Value &rhs) { return lhs.index == rhs.index; })
| ranges::v3::view::transform([](auto &&vs){
int index, cost = 0;
for(auto& v : vs) { index=v.index; cost+=v.cost;}
return Value{index, cost};
});
auto it = ranges::v3::copy(merged.begin(), merged.end(), values.begin()).second;
values.erase(it, values.end());
}
Also, don't forget plain old for-loop:
void merge(std::vector<Value> &values)
{
std::sort(values.begin(), values.end(), [](auto &lhs , auto &rhs) { return lhs.index < rhs.index; });
std::size_t j = 0;
for(std::size_t i = 0; i < values.size(); i++)
{
if(j>0 && values[j-1].index == values[i].index)
{
values[j-1].cost += values[i].cost;
continue;
}
if(j!=i) values[j]=std::move(values[i]);
j++;
}
values.erase(values.begin()+j, values.end());
}

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.

Counting struct elements in 2D vector C++

I have a 2D vector of structures of this type
typedef struct box
{
int boxVal;
char boxTakenBy;
} box;
I have myvector defined as:
vector<vector<box> > myvector(10,vector<box>(10))
My goal is to count number of elements with boxTakenBy == 'X'. I tried:
int mycount = std::count_if( myvector.begin(), myvector.end(),
[](const box &p ) { return p.boxTakenBy == 'X'; });
I am getting compilation error :
no match for call to ‘<lambda(const box&)>) (std::vector<box >&)
Not sure if my approach is wrong or just the syntax. Please correct if you find any syntax issue or suggest if any better approach is out there.
As mentioned by hauron elements of myvector are not boxes but vector<box>s. So what you need to do it iterate over 2 dimensions of myvector.
You can combine std::accumulate (to accumulate the sum) and std::count_if (to count the inner elements satisfying your condition ( == 'X') to achieve that like so:
#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
struct box
{
int boxVal;
char boxTakenBy;
};
int main(){
using namespace std;
vector<vector<box> > myvector(10, vector<box>(10));
myvector[0][0].boxTakenBy = 'X';
myvector[2][0].boxTakenBy = 'X';
myvector[2][7].boxTakenBy = 'X';
myvector[5][7].boxTakenBy = 's';
int total_count = std::accumulate(myvector.begin(), myvector.end(), 0,
[](int acc, const vector<box>& curr)
{
return acc + std::count_if(curr.begin(), curr.end(),
[](const box& b ) { return b.boxTakenBy == 'X'; });
}
);
std::cout << total_count << '\n';
}
LIVE DEMO
You have two levels of vectors, so you need to traverse both.
You can use count_if to count the elements in each "inner" vector, then sum the results with accumulate:
int count = std::accumulate(myvector.begin(),
myvector.end(),
0,
[](int i, const vector<box>& bs)
{ return i + std::count_if(bs.begin(),
bs.end(),
[](const box& b)
{ return b.boxTakenBy == 'X';}); });
or, pulling out the innermost function and abstracting out the character:
auto takenBy = [](char c) { return [=](const box& b) { return b.boxTakenBy == c; };};
int count = std::accumulate(myvector.begin(),
myvector.end(),
0,
[&](int i, const vector<box>& bs)
{ return i + std::count_if(bs.begin(),
bs.end(),
takenBy('X')); });
Another solution can be to use std::for_each and std::count_if as following:
int mycount;
std::for_each( myvector.begin(), myvector.end(),
[&mycount](std::vector<box> const &p )
{ mycount += std::count_if(p.begin(),p.end(),[](box const & q){return q.boxTakenBy == 'X'; });
});
Standard library algorithms are great and everything but sometimes I think a ranged-based for loop is simpler:
auto mycount = 0;
for(const auto& row : myvector)
for(auto& item: row)
if (item.boxTakenBy == 'X') ++mycount;
Live demo.

How to get the sorted index of a vector?

I have a vector. It is not sorted. Now I want to get its indices which will sort the vector. For example vector<int> v{1, 3, 2}, sorted indices are {0, 2, 1} because v[0] <= v[2] <= v[1]. If two equal, doesn't matter which one go first.
What you're looking for is called tag sorting (or index sorting). Here is a minimal example using lambdas in C++11:
#include <algorithm>
#include <numeric>
#include <iostream>
#include <vector>
template<typename T>
std::vector<std::size_t> tag_sort(const std::vector<T>& v)
{
std::vector<std::size_t> result(v.size());
std::iota(std::begin(result), std::end(result), 0);
std::sort(std::begin(result), std::end(result),
[&v](const auto & lhs, const auto & rhs)
{
return v[lhs] < v[rhs];
}
);
return result;
}
int main()
{
std::vector<char> v{'a', 'd', 'b', 'c'};
auto idxs = tag_sort(v);
for (auto && elem : idxs)
std::cout << elem << " : " << v[elem] << std::endl;
}
Live on Coliru

How to sort a sorted vector while maintaining the previous orders

I have following structure
struct Mydate
{
int UserId;
string name;
};
vector<Mydate> v1;
1: sort the vector by UserId
2: Sort the sorted vector by name while maintaining the previous order
For example
v1.push_back(make_pair(100, "d"));
v1.push_back(make_pair(100, "q"));
v1.push_back(make_pair(102, "m"));
v1.push_back(make_pair(102, "d"));
v1.push_back(make_pair(100, "c"));
( sort function can be used first for UserId but when we sort it agin by name, it override the previous order)
can we see output in follwoing format:
(100,c) , (100, d), (100, q), (102,d), (102, m)
Please can some one help me out??
You can define an operator< member function like this:
operator<(const Mydate & rhs)
{
if (UserId < rhs.UserId)
{
return true;
}
else if (UserId == rhs.UserId)
{
if (name < rhs.name)
{
return true;
}
}
return false;
}
You can define your own comparator for std::sort
vector<Mydate> v1;
// ...
std::sort(v1.begin(), v1.end(), [](Mydate const &a, Mydate const &b) {
return (a.UserId == b.UserId)? (a.name < b.name) : (a.UserId < b.UserId);});
Or instead of a class you can use a std::pair:
using Mydate = std::pair<int, std::string>;
std::pairs are compared lexicographically which is what you want. And then use std::sort as:
std::vector<Mydate> v1;
//...
std::sort(v1.begin(), v1.end());
It seems you mean the following
#include <iostream>
#include <string>
#include <vector>
#include <tuple>
#include <algorithm>
struct Mydate
{
int UserId;
std::string name;
};
std::vector<Mydate> v1;
int main()
{
v1.push_back( { 100, "d" } );
v1.push_back( { 100, "q" } );
v1.push_back( { 102, "m" } );
v1.push_back( { 102, "d" } );
v1.push_back( { 100, "c" } );
std::sort( v1.begin(), v1.end(),
[]( const Mydate &a, const Mydate &b )
{
return std::tie( a.UserId, a.name ) < std::tie( b.UserId, b.name );
} );
for ( const Mydate &item : v1 )
{
std::cout << item.UserId << '\t' << item.name << std::endl;
}
}
The program output is
100 c
100 d
100 q
102 d
102 m
Custom comparator approach is preferred one, but, for sake of completeness, multiple sorting approach should be mentioned. Sometimes it might be preferred (usually when you want to be able to choose sorting rules dynamically).
To sort entries by some property A, where elements with same A would be sorted by property B, you need to use bottoms-up approach: sort by B first, then sort by A, preserving relative order of equivalent elements (stable sort).
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Mydate
{
int UserId;
std::string name;
};
int main()
{
std::vector<Mydate> v {{100, "d"}, {100, "q"}, {102, "m"}, {102, "d"}, {100, "c"}};
std::sort(v.begin(), v.end(), [](auto& l, auto& r){return l.name < r.name;});
std::stable_sort(v.begin(), v.end(), [](auto& l, auto& r){return l.UserId < r.UserId;});
for(const auto& d: v)
std::cout << d.UserId << ' ' << d.name << '\n';
}
If you insist on sorting in 2 passes, use std::stable_sort for the second pass.