Container/Structure to Initialize Based on Position - c++

I have some data who's index is part of it's information. Therefore I'd like this information to be somehow used in the construction of the object to be placed into the container.
I'm trying to capture the smallest value with bit index.
set<int> numbers{1, 3, 5, 6, 10, 13, 24};
vector<decltype(numbers)::key_type> int_log(log2(numeric_limits<decltype(numbers)::key_type>::max()));
generate(int_log.begin(), int_log.end(), []{static auto i = 0; return 1 << ++i;});
auto maximum = 0u;
for_each(numbers.begin(), numbers.end(), [&](auto i){unsigned int index = log2(i); maximum = max(maximum, index); int_log[index] = min(int_log[index], i);});
for_each(int_log.begin(), next(int_log.begin(), maximum + 1), [](auto i){cout << i << endl;});
There are two things that I'd like to accomplish:
Have elements of int_log initialize themselves to the correct value according to their index.
Only create the elements as that I need, rather than all possible elements up front.
The only solutions I'm thinking of for these questions are very involved map or set containers. Can someone give me a simpler solution?

Related

Is it possible to make a vector of ranges in cpp20

Let's say I have a a vector<vector<int>>. I want to use ranges::transform in such a way that I get
vector<vector<int>> original_vectors;
using T = decltype(ranges::views::transform(original_vectors[0], [&](int x){
return x;
}));
vector<int> transformation_coeff;
vector<T> transformed_vectors;
for(int i=0;i<n;i++){
transformed_vectors.push_back(ranges::views::transform(original_vectors[i], [&](int x){
return x * transformation_coeff[i];
}));
}
Is such a transformation, or something similar, currently possible in C++?
I know its possible to simply store the transformation_coeff, but it's inconvenient to apply it at every step. (This will be repeated multiple times so it needs to be done in O(log n), therefore I can't explicitly apply the transformation).
Yes, you can have a vector of ranges. The problem in your code is that you are using a temporary lambda in your using statement. Because of that, the type of the item you are pushing into the vector later is different from T. You can solve it by assigning the lambda to a variable first:
vector<vector<int>> original_vectors;
auto lambda = [&](int x){return x;};
using T = decltype(ranges::views::transform(original_vectors[0], lambda));
vector<T> transformed_vectors;
transformed_vectors.push_back(ranges::views::transform(original_vectors[0], lambda));
It is not possible in general to store different ranges in a homogeneous collection like std::vector, because different ranges usually have different types, especially if transforms using lambdas are involved. No two lambdas have the same type and the type of the lambda will be part of the range type. If the signatures of the functions you want to pass to the transform are the same, you could wrap the lambdas in std::function as suggested by #IlCapitano (https://godbolt.org/z/zGETzG4xW). Note that this comes at the cost of the additional overhead std::function entails.
A better option might be to create a range of ranges.
If I understand you correctly, you have a vector of n vectors, e.g.
std::vector<std::vector<int>> original_vector = {
{1, 5, 10},
{2, 4, 8},
{5, 10, 15}
};
and a vector of n coefficients, e.g.
std::vector<int> transformation_coeff = {2, 1, 3};
and you want a range of ranges representing the transformed vectors, where the ith range represents the ith vector's elements which have been multiplied by the ith coefficient:
{
{ 2, 10, 20}, // {1, 5, 10} * 2
{ 2, 4, 8}, // {2, 4, 8} * 1
{15, 30, 45} // {5, 10, 15} * 3
}
Did I understand you correctly? If yes, I don't understand what you mean with your complexity requirement of O(log n). What does n refer to in this scenario? How would this calculation be possible in less than n steps? Here is a solution that gives you the range of ranges you want. Evaluating this range requires O(n*m) multiplications, where m is an upper bound for the number of elements in each inner vector. I don't think it can be done in less steps because you have to multiply each element in original_vector once. Of course, you can always just evaluate part of the range, because the evaluation is lazy.
C++20
The strategy is to first create a range for the transformed i-th vector given the index i. Then you can create a range of ints using std::views::iota and transform it to the inner ranges:
auto transformed_ranges = std::views::iota(0) | std::views::transform(
[=](int i){
// get a range containing only the ith inner range
auto ith = original_vector | std::views::drop(i) | std::views::take(1) | std::views::join;
// transform the ith inner range
return ith | std::views::transform(
[=](auto const& x){
return x * transformation_coeff[i];
}
);
}
);
You can now do
for (auto const& transformed_range : transformed_ranges){
for (auto const& val : transformed_range){
std::cout << val << " ";
}
std::cout<<"\n";
}
Output:
2 10 20
2 4 8
15 30 45
Full Code on Godbolt Compiler Explorer
C++23
This is the perfect job for C++23's std::views::zip_transform:
auto transformed_ranges = std::views::zip_transform(
[=](auto const& ith, auto const& coeff){
return ith | std::views::transform(
[=](auto const& x){
return x * coeff;
}
);
},
original_vector,
transformation_coeff
);
It's a bit shorter and has the added benefit that transformation_coeff is treated as a range as well:
It is more general, because we are not restricted to std::vectors
In the C++20 solution you get undefined behaviour without additional size checking if transformation_coeff.size() < original_vector.size() because we are indexing into the vector, while the C++23 solution would just return a range with fewer elements.
Full Code on Godbold Compiler Explorer

Virtually defragment a fragmented memory as if it was contiguous in c++

is there a way or is it possible to take e.g 10 memory regions (e.g. pointers with given size) and create a sort of overlay such that they can be handled/treated as contiguous?
The use case would be something like reconstruct a message out of "n" frames without copying them around.
Of course the "n" frames are appended/prependend with a header which should be stripped in order to reconstruct the information. Moreover a variable could be e.g. splitted across two consecutive frames.
Few more details for future help.
Otter solution is quite nice but it lacks the possibility to lay a structure on top of multiple boost::join-ed block.
Of course a std::copy of the joined block will create a contiguous copy of all the interested and fragmented regions but in my case i would like it to be "virtual" due to performance constraints.
Regards,
boost::range::join is a great helper here - link. When working with random access ranges it will also produce random access range with quick access to elements. As the manual tells The resultant range will have the lowest common traversal of the two ranges supplied as parameters
Also when working with plain memory boost::make_iterator_range cound help.
Take a look at this short example.
int arr1[] = { 0, 1, 2, 3, 4, 5 }; // let's join these 3 plain memory arrays
int arr2[] = { 6, 7, 8, 9 };
int arr3[] = { 10, 11, 12};
int* mem1 = arr1; // let's make the example more complicated
int* mem2 = arr2; // because int arr1[] with known size will be recognized
int* mem3 = arr3; // as a range by boost::join
auto res1 = boost::range::join(boost::make_iterator_range(mem1, mem1 + 6),
boost::make_iterator_range(mem2, mem2 + 4)); // join 2 ranges by pointer arithmetics
auto res2 = boost::range::join(res1, // join previously joined range
boost::make_iterator_range(mem3, mem3 + 3));
for (auto& r : res2) // the resulted range is iterable
{
std::cout << r << "\n";
}
std::cout << res2[12]; // outputs '12', note that this result
// was eventually got by pointer arithmetics
// applyed to mem3

How can I improve the following lambda function for finding the first 4 elements in a vector

For practice, I am trying to copy the first 4 entries different than 2 from a vector of integers using copy_if.
This seems to work but if there is a better way of writing this lambda then I'd like to learn the proper way. Cheers.
vector<int> first_vector = {2,8,50,2,4,5,9,12};
vector<int> second_vector (first_vector.size());
int count_elem=0;
auto it = copy_if(first_vector.begin(),first_vector.end(),second_vector.begin(),
[&count_elem]
(int i){
if(i!=2 && count_elem!=4)
{
count_elem++;
return 1;
}
return 0;});
Since you are not copying all of the values from first_vector to second_vector, you should not initialize second_vector to hold the same number of elements as first_vector. You are creating more elements than you want, where the extra elements are value-initialized to 0.
I would suggest reserve()'ing the size of second_vector instead and then use std::back_inserter as the destination iterator to copy to. That way, second_vector ends up with only the values you want pushed and nothing else.
That would also eliminate the need for the count_elem variable. You can use second_vector.size() to know how many values have been pushed into the vector.
std::vector<int> first_vector = {2, 8, 50, 2, 4, 5, 9, 12};
std::vector<int> second_vector;
second_vector.reserve(4);
std::copy_if(
first_vector.begin(), first_vector.end(),
std::back_inserter(second_vector),
[&](int i){
return ((i != 2) && (second_vector.size() < 4));
}
);
Do note, however, that this use of std::copy_if() will iterate through the entire first_vector, it will not stop iterating once 4 values have been pushed to second_vector. It would be more efficient to simply run your own loop instead so you can break it as soon as possible:
std::vector<int> first_vector = {2, 8, 50, 2, 4, 5, 9, 12};
std::vector<int> second_vector;
second_vector.reserve(4);
for(int i : first_vector) {
if (i != 2) {
second_vector.push_back(i);
if (second_vector.size() == 4)
break;
}
}

How to find the vector element that indexes the lowest value in an array

To simplify my issue, let's say I have an array that stores some values:
int Costs[5] = {40, 50, 10, 10, 30};
and I have a vector which I use to store IDs
std::vector<int> id = { 4,0,1 };
so that, for example, Costs [ id [ 0 ] ] will return the value 30 and so on
I need the INDEX number whose value would point to the lowest value in the Costs array.
In my example the index that I need would be 0 since Costs[id[0]] is lower than Costs[id[1]] or Costs[id[2]]
So if I were to make a function, I would NOT want it to return what id[0] holds; I would want it to return the 0, which is the index / element number.
I would be grateful if anyone could help me code this.
This is taken straight from http://en.cppreference.com/w/cpp/algorithm/min_element
If i understand correctly you want to get the index of the minimal element in an array
This should work both with vectors and arrays alike
std::vector<int> v{3, 1, 4, 1, 5, 9};
// We need to get the min value
std::vector<int>::iterator result = std::min_element(std::begin(v), std::end(v));
// Then we get the index of the value in the array
std::cout << "min element at: " << std::distance(std::begin(v), result);
What you can do is first get all the values of Cost array in the position of id values and store them in an temporary std::vector.
According to your code, you can use a iterator over the values contained in ids, inside the loop you use std::vector push_back() function to add the elements in position of Cost[id].
Then apply the above mentioned std::min_element and std::distance to get the index. Note that this will return the index of the id vector, getting the value from there is just a matter of ids[index]
Here's full working test code. Thank you Jointts for explaining how to do it.
int Costs[5] = { 40, 50, 10, 0, 90 };
std::vector<int> id = { 4,1,0 };
std::vector<int> temp;
for (int i = 0; i < id.size(); i++)
{
temp.push_back(Costs[id[i]]);
}
std::vector<int>::iterator lowest = std::min_element(std::begin(temp), std::end(temp));
std::cout << "min element at: " << std::distance(std::begin(temp), lowest) << std::endl;

Fast union building of multiple vectors in C++

I’m searching for a fast way to build a union of multiple vectors in C++.
More specifically: I have a collection of vectors (usually 15-20 vectors with several thousand unsigned integers; always sorted and unique so they could also be an std::set). For each stage, I choose some (usually 5-10) of them and build a union vector. Than I save the length of the union vector and choose some other vectors. This will be done for several thousand times. In the end I'm only interested in the length of the shortest union vector.
Small example:
V1: {0, 4, 19, 40}
V2: {2, 4, 8, 9, 19}
V3: {0, 1, 2, 4, 40}
V4: {9, 10}
// The Input Vectors V1, V2 … are always sorted and unique (could also be an std::set)
Choose V1 , V3;
Union Vector = {0, 1, 2, 4, 19, 40} -> Size = 6;
Choose V1, V4;
Union Vector = {0,4, 9, 10, 19 ,40} -> Size = 6;
… and so on …
At the moment I use std::set_union but I’m sure there must be a faster way.
vector< vector<uint64_t>> collection;
vector<uint64_t> chosen;
for(unsigned int i = 0; i<chosen->size(); i++) {
set_union(collection.at(choosen.at(i)).begin(),
collection.at(choosen.at(i)).end(),
unionVector.begin(),
unionVector.end(),
back_inserter(unionVectorTmp));
unionVector.swap(unionVectorTmp);
unionVectorTmp.clear();
}
I'm grateful for every reference.
EDIT 27.04.2017
A new Idea:
unordered_set<unsigned int> unionSet;
unsigned int counter = 0;
for(const auto &sel : selection){
for(const auto &val : sel){
auto r = unionSet.insert(val);
if(r.second){
counter++;
}
}
}
If they're sorted you can roll your own thats O(N+M) in runtime. Otherwise you can use a hashtable with similar runtime
The de facto way in C++98 is set_intersection, but with c++11 (or TR1) you can go for unordered_set, provided the initial vector is sorted, you will have a nice O(N) algorithm.
Construct an unordered_set out of your first vector
Check if the elements of your 2nd vector are in the set
Something like that will do:
std::unordered_set<int> us(std::begin(v1), std::end(v1));
auto res = std::count_if(std::begin(v2), std::end(v2), [&](int n) {return us.find(n) != std::end(us);}
There's no need to create the entire union vector. You can count the number of unique elements among the selected vectors by keeping a list of iterators and comparing/incrementing them appropriately.
Here's the pseudo-code:
int countUnique(const std::vector<std::vector<unsigned int>>& selection)
{
std::vector<std::vector<unsigned int>::const_iterator> iters;
for (const auto& sel : selection) {
iters.push_back(sel.begin());
}
auto atEnd = [&]() -> bool {
// check if all iterators equal end
};
int count = 0;
while (!atEnd()) {
const int min = 0; // find minimum value among iterators
for (size_t i = 0; i < iters.size(); ++i) {
if (iters[i] != selection[i].end() && *iters[i] == min) {
++iters[i];
}
}
++count;
}
return count;
}
This uses the fact that your input vectors are sorted and only contain unique elements.
The idea is to keep an iterator into each selected vector. The minimum value among those iterators is our next unique value in the union vector. Then we increment all iterators whose value is equal to that minimum. We repeat this until all iterators are at the end of the selected vectors.