I want to increase each element in a std::vector<size_t> with length 256 by one, but depending on same position of a std::bitset<256> (if equal 1).
Code below can be edited / compiled here.
My question is, can I get away from the for loop and get in some fast logical operator?
#include <iostream>
#include <bitset>
#include <vector>
#include <iterator>
#include <algorithm>
#define SIZE 3
int main() {
size_t size=SIZE;
std::vector<size_t> v(SIZE); v={3,0,7};
std::bitset<SIZE> b("110");
for (size_t i=0; i<size; ++i)
{
if (b[size-1-i]) // reverse
{
++v[i];
}
}
std::copy ( v.begin()
, v.end()
, std::ostream_iterator<size_t>(std::cout, ",") );
// 3+1,0+1,7+0
// => 4,1,7
return 0;
}
Since bitset doesn't have iterators we can't simply use std::transform. But we can create iterator-like wrapper around size_t and use it like index:
#include <iostream>
#include <bitset>
#include <vector>
#include <iterator>
#include <algorithm>
#define SIZE 3
class IntegralIterator
{
public:
IntegralIterator(size_t v = 0) : value(v) {}
size_t operator*()
{
return value;
}
IntegralIterator& operator++()
{
++value;
return *this;
}
private:
size_t value;
};
int main() {
size_t size=SIZE;
std::vector<size_t> v(SIZE); v={3,0,7};
std::bitset<SIZE> b("110");
std::transform(v.begin(), v.end(), IntegralIterator(), v.begin(),
[&](size_t s, size_t index)
{
return s + b[size-1-index];
});
std::copy(v.begin(), v.end(),
std::ostream_iterator<size_t>(std::cout, ",") );
return 0;
}
Related
I have a vector of elements of type uint8 which I am copying into one std::array. After some operations again I need to copy the elements from std::array to a vector.Please find the code below
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
#include <iostream>
#include <vector>
#include <array>
#include <cstdint>
#include <limits>
#include <algorithm>
std::array<std::uint32_t, 5> elem_arr ;
void copy_from_vector(std::vector<std::uint32_t> elem_vec)
{
std::copy(elem_vec.begin(),elem_vec.end(),elem_arr.begin());
}
std::vector<std::uint32_t> copy_from_array()
{
std::vector<std::uint32_t> ele_vec_copy {elem_arr.begin(),elem_arr.end()};
return ele_vec_copy;
}
int main()
{
std::vector<std::uint32_t> ele_vec {1,2,3};
copy_from_vector(ele_vec);
auto ele_vec_copy = copy_from_array();
for(auto ele : ele_vec_copy)
std::cout << ele << std::endl;
return 0;
}
output:
======
1
2
3
0
0
Now the problem is my array size is 5 but vector having only 3 elements. when I copy the elements from the array to a new vector I am getting extra 2 zeros. How can I get the output as below
output:
======
1
2
3
You could copy by size of vector.
#include <iostream>
#include <vector>
#include <array>
#include <cstdint>
#include <limits>
#include <algorithm>
int main()
{
std::array<std::uint32_t, 5> elem_arr ;
std::vector<std::uint32_t> ele_vec {1,2,3};
std::copy(ele_vec.begin(),ele_vec.end(),elem_arr.begin());
std::vector<std::uint32_t> ele_vec_copy { elem_arr.begin() , elem_arr.begin() + ele_vec.size() };
for(auto ele : ele_vec_copy)
std::cout << ele << std::endl;
return 0;
}
run online
After you edited the question
It is not possible to know how many elements used/set in std::array but this feature could be mimic by choosing a unique value which represents the element is null or not set like nullptr. But it comes with a constraint, you must not use the unique value at somewhere else in the array.
So the possible implementation is :
#include <iostream>
#include <vector>
#include <array>
#include <cstdint>
#include <limits>
#include <algorithm>
#include <limits>
std::array<std::uint32_t, 5> elem_arr;
void copy_from_vector(std::vector<std::uint32_t> elem_vec)
{
std::copy(elem_vec.begin(),elem_vec.end(),elem_arr.begin());
}
std::vector<std::uint32_t> copy_from_array()
{
std::vector<std::uint32_t> ele_vec_copy;
std::copy_if( elem_arr.begin() , elem_arr.end() ,
std::back_inserter( ele_vec_copy ) ,
[]( std::uint32_t val ) {
return val != std::numeric_limits<std::uint32_t>::max();
} );
return ele_vec_copy;
}
int main()
{
elem_arr.fill( std::numeric_limits<std::uint32_t>::max() );
std::vector<std::uint32_t> ele_vec {1,2,3};
copy_from_vector(ele_vec);
auto ele_vec_copy = copy_from_array();
for(auto ele : ele_vec_copy)
std::cout << ele << std::endl;
return 0;
}
run online
Or store the elements as std::optional and don't copy null elements.
Possible implementation is :
#include <iostream>
#include <vector>
#include <array>
#include <cstdint>
#include <limits>
#include <algorithm>
#include <limits>
#include <optional>
std::array<std::optional<std::uint32_t>, 5> elem_arr;
void copy_from_vector(std::vector<std::uint32_t> elem_vec)
{
std::transform( elem_vec.begin() , elem_vec.end() ,
elem_arr.begin() ,
[]( auto val ) { return std::optional<std::uint32_t>{ val }; }
);
}
std::vector<std::uint32_t> copy_from_array()
{
std::vector<std::uint32_t> ele_vec_copy;
std::vector<std::optional<std::uint32_t>> non_null_elements;
std::copy_if( elem_arr.begin() , elem_arr.end() ,
std::back_inserter( non_null_elements ) ,
[]( auto val ) {
return val;
} );
std::transform( non_null_elements.begin(), non_null_elements.end() ,
std::back_inserter( ele_vec_copy ) ,
[]( auto val ) { return *val; }
);
return ele_vec_copy;
}
int main()
{
std::vector<std::uint32_t> ele_vec {1,2,3};
copy_from_vector(ele_vec);
auto ele_vec_copy = copy_from_array();
for(auto ele : ele_vec_copy)
std::cout << ele << std::endl;
return 0;
}
run online
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.
I was trying to find how many element are less than a certain X in a multiset by using:
mset.lower_bound(X) - mset.begin()
But it didn't work. Any workarounds?
You may use:
std::distance(mset.begin(), mset.lower_bound(X));
To make it robust, use:
size_t count = 0;
auto found = mset.lower_bound(X);
if ( found != mset.end() )
{
count = std::distance(mset.begin(), found);
}
If computing the number of items below a lower bound is done frequently, and items are inserted seldom, you might get better performance using a std::vector and keeping it sorted.
Particularly if T is moveable.
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
auto insert(std::vector<std::string>& v, std::string s)
{
auto lb = std::lower_bound(v.begin(), v.end(), s);
v.insert(lb, std::move(s));
}
int main()
{
std::vector<std::string> v;
insert(v, "goodbye");
insert(v, "world");
insert(v, "cruel");
auto count = std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), "goodbye"));
std::cout << count << std::endl;
std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
but why still use std::distance with vector?
Because we might change our mind if we choose to profile with different container types, so it's better to be idiomatic. The standard library contains specialisations to ensure that the idiom is optimal:
#include <vector>
#include <set>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
template<class Range, class Value, class Pred = std::less<>>
auto lower_bound(Range&& range, Value&& v, Pred&& pred = Pred())
{
return std::lower_bound(std::begin(range), std::end(range),
std::forward<Value>(v),
std::forward<Pred>(pred));
}
template<class Container>
auto insert(Container&& v, std::string s)
{
auto lb = lower_bound(v, s);
v.insert(lb, std::move(s));
}
template<class Range, class OutIter>
auto copy(Range&& range, OutIter dest)
{
return std::copy(std::begin(range), std::end(range), dest);
}
auto test = [](auto&& container)
{
insert(container, "goodbye");
insert(container, "world");
insert(container, "cruel");
auto count = std::distance(std::begin(container), lower_bound(container, "goodbye"));
std::cout << count << std::endl;
copy(container, std::ostream_iterator<std::string>(std::cout, "\n"));
};
int main()
{
test(std::vector<std::string>{});
test(std::multiset<std::string>{});
}
I want to use the richness of <iterator> with arrays held by unique_ptr.
Here's the code I'd like to write ajuxt the code I am currently obliged to write:
void question() {
const int len = 10;
int a[len];
unique_ptr<int[]> p(new int[len]);
// i can do this with a bare array
for_each(begin(a), end(a), [](int& v) { v = 0; });
// but this doesn't compile cuz unique_ptr<T[]> doesn't implement dereference
// for_each(begin(*p), end(*p), [](int& v) { v = 0; });
// this works, but ugly, and begin() and end() are not abstracted.
for_each(&p[0], &p[len], [](int& v) { v = 0; });
// how best to make iterators for an array within a unique_ptr?
}
Or might I be much better off using a container class instead of an array?
ELABORATION:
My full use case is a Buffer object that contains a raw array of audio samples that will be passed to an audio device. The length of the array is determined at Buffer construction and then remains fixed.
I'm not using a container class because the data must be contiguous in memory. But I want to iterate over the buffer to fill it with data.
#include <iostream>
#include <algorithm>
#include <cmath>
#include <iterator>
using namespace::std;
struct Buffer {
unique_ptr<double[]> buf;
size_t len;
int frameRate;
Buffer(size_t len) : buf(new double[len]), len(len) {}
};
class Osc {
double phase, freq;
public:
Osc(double phase, double freq) : phase(phase), freq(freq) {}
void fill(Buffer& b) {
double ph = phase;
for_each(b.buf.get(), next(b.buf.get(), b.len), [&ph, &b](double& d) {
d = sin(ph);
ph += 1.0/b.frameRate;
});
}
};
int main() {
Buffer buf(100);
Osc osc(0, 440);
osc.fill(buf);
return 0;
}
#include <iostream>
#include <algorithm>
#include <memory>
void question() {
const int len = 10;
std::unique_ptr<int[]> p(new int[len]);
int x = 0;
std::for_each(std::next(p.get(), 0), std::next(p.get(), len), [&](int& a) { a = ++x; }); // used std::next(p.get(), 0) instead of p.get().
std::for_each(std::next(p.get(), 0), std::next(p.get(), len), [](int a) { std::cout << a << "\n" ;});
}
int main()
{
question();
}
The below is a simple parallel program to calculate the sum of elements in a standard vector using tbb.
Can someone please help me understand why it is outputing a wrong result?
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tbb/tbb.h>
struct Sum {
int value;
Sum() : value(0) {}
Sum(Sum&s, tbb::split) : value(0) {}
void operator()(const tbb::blocked_range<std::vector<int>::iterator>& r) {
value = std::accumulate(r.begin(), r.end(), 0);
}
void join(Sum& rhs) { value += rhs.value; }
};
int main()
{
std::vector<int> a(100);
std::fill(a.begin(), a.end(), 1);
Sum sum;
tbb::parallel_reduce(tbb::blocked_range<std::vector<int>::iterator>(a.begin(), a.end()), sum);
std::cout << sum.value << std::endl;
return 0;
}
Since you use accumulate wrong. It should be
value = std::accumulate(r.begin(), r.end(), value);
Why don't you use the functional form of tbb_parallel_reduce? It avoids the need for your struct Sum and looks more intuitive, for example (not tested)
typedef tbb::blocked_range<std::vector<int>::iterator> range_type;
auto sum=tbb_parallel_reduce(range_type(a.begin(),a.end()), 0,
[](range_type const&r, int init)
{ return std::accumulate(r.begin(),r.end(),init); },
std::plus<int>());