modify every element of collection - c++

Is there any common way to get rid of custom 'assign' functor? std::transform could be great but according to c++ standard it prohibits modification of the source elements
The goal is to modify collection elements using as more declarative approach as possible
template <typename T>
struct assign : std::binary_function<T, T, void> {
void operator()( const T& source, T& dest ) {
dest = source;
}
};
int main() {
static boost::array<int, 5> arr = { 1, 2, 3, 4, 5 };
std::for_each( arr.begin(), arr.end(),
boost::bind( assign<int>(), boost::bind( std::plus<int>(), _1, 3 ), _1 ) );
return 0;
}

std::transform() does allow the output iterator to point to the same element as the beginning of your input range. See here. The code example shows essentially this in the line demonstrating a transform with two input ranges. The output iterator is the same as the first input iterator. Does that make it more palatable?

Try Boost.Lambda:
int main() {
using namespace boost::lambda;
static boost::array<int, 5> arr = { 1, 2, 3, 4, 5 };
std::for_each( arr.begin(), arr.end(), _1 += 3 );
return 0;
}
However, what about just a "for_each" loop:
int main() {
static boost::array<int, 5> arr = { 1, 2, 3, 4, 5 };
BOOST_FOREACH(int& n, arr) {
n += 3;
}
return 0;
}

What #gregg said plus:
The wording in the standard (N1905 25.2.3 paragraph 2) forbids the transformation function from directly modifying elements in the given ranges, i.e. it cannot write to an input iterator. It is only supposed to calculate a value, which the transform function then assigns to the result iterator. In fact, paragraph 5 explicitly allows result to be equal to first.
I guess this may allow implementations to perform safety-checks or optimizations in specific cases.
For instance, suppose transform were specialized for std::vector<char>. On a 32 bit machine, the implementation could unroll the main loop 4 times and perform 32 bit loads and stores instead of 8 bit ones. Clearly this would not work, if the first call to the transformation function modified the input range (the remaining 3 calls before the store would then operate on dirty data).
Here's C++03 one-liner to add 3 to each value off arr:
std::transform(arr.begin(), arr.end(), arr.begin(), std::bind1st(std::plus<int>(), 3));

Related

Initializing some elements of vector of defined size

Is there a way to initialize first few elements of a vector after defining the size of the vector like -
vector<int> vec (10);
This doesn't work and produces a compiler error -
vector<int> vec(10) {1,2,3};
For example with arrays we can do the same thing like -
int arr[5] {1,2,3}; // This will initialize the first 3 elements of the array to 1,2,3 and the remaining two to 0.
In short, no. Your can fill out the entire list of things you want to be in the vector:
vector<int> vec{1, 2, 3, 0, 0, 0, 0, 0, 0, 0};
Which will give you a vector of 10 elements.
Or, you can create the vector, then call resize to make it larger (filling the remaining elements with 0):
vector<int> vec{1, 2, 3};
vec.resize(10);
You generally don't need to do this kind of thing to vector though, because unlike array, you can extend vector as needed, after creation:
vector<int> vec{1, 2, 3};
vec.push_back(4);
There isn't a way to do it all in one line like you can with an array. You can use
vector<int> vec{1,2,3};
vec.resize(10);
but that does make the code a little less easy to use. Another option is to wrap that in a function like
template <typename T>
auto make_sized_vector(std::intializer_list<T> il, std::size_t size = 0)
{
const auto vec_size = std::max(size, il.size());
vector<T> vec; // create vector
vec.reserve(vec_size); // allocate all the storage needed
vec.assign(il); // assign the elements
vec.resize(vec_size); // set the rest to zero
return vec;
}
and then you can use that like
auto vec = make_sized_vector<int>({1, 2, 3}, 10);
If you are concerned about passing the std::intializer_list by value see why is `std::initializer_list` often passed by value? for why that really isn't a concern.
In case you want to initialize a vector the way you describe, all at once, so that it can become (e.g.) a const member, this is always possible in C++, with just a bit of ugliness and twisting. Let’s say you have a class:
struct SomeClass {
SomeClass(const std::vector<int> &start, int rest, std::size_t size);
const std::vector<int> some_vector_; // This is const!
};
What the constructor could look like:
SomeClass::SomeClass(const std::vector<int> &start, int rest, std::size_t size)
: some_vector_{[&start, rest, size] {
std::vector<int> some_vector;
some_vector.reserve(size);
some_vector.insert(some_vector.end(), start.begin(), start.end());
some_vector.insert(some_vector.end(), size - start.size(), rest);
return some_vector;
}()} {}
Basically the problem boils down to: How do I do “something procedural” in an initializer list? To which the answer is: You invoke a function that returns the desired type.
To test the construct above:
#include <cstdint>
#include <iostream>
#include <vector>
namespace { /* SomeClass stuff from above goes here. */ }
int main() {
SomeClass sc{{1, 2, 3}, 0, 10};
for (int i : sc.some_vector_) std::cout << i << '\n';
}
There are (of course) plenty of ways to make it (slightly) more efficient if needed, such as
a templated variadic constructor to create the initial part of the vector,
a templated perfect-forwarding constructor to benefit from R-value containers, and
as a combined benefit of the above, arbitrary iterable containers as inputs and as the const member.

How do I add numbers of an array to another array?

I want to add the numbers of the array {1, 2, 3} to the array {7, 4, 6} so I can get an array {8, 6, 9} like this:
int main(){
int arr[] = {1, 2, 3};
int arr2[] = {7, 4, 6};
arr += arr2; // invalid operands of types ‘int [3]’ and ‘int*’ to binary ‘operator+’
}
std::valarray allows you to do this, with some minor changes to your code:
#include <iostream>
#include <valarray>
int main() {
std::valarray<int> arr{1, 2, 3};
std::valarray<int> arr2{7, 4, 6};
arr += arr2;
std::cout << arr[0] << arr[1] << arr[2];
}
Compared to the other C++ standard library containers, std::valarray is equipped with a fair number of "bulk" mathematical operations.
If the arrays are "fixed" at compile time using a constexpr function is also a good idea:
#include <array>
#include <iostream>
//
// Define an add function template
//
// This will provide compile time checking of equal array sizes
// so we have no need to check that condition at runtime (over and over again).
//
// By making it constexpr we can also use this function's results at compile time (See below).
// Also by using std::array you have a good example on how C++ can return
// arrays from functions.
//
// template makes the code reusable for multiple types and array sizes.
//
// typename type_t makes this function usable for all kinds of types so it isn't restricted to ints
// std::size_t N allows for the compiler to generate correct code for positive array sizes
//
// arr1, arr2 :
// Passed as const because the add function should never change the content of those arrays.
// type_t(&arr1)[N] is C++'s way of passing an array of known size
// so you don't have to pass pointers, pointers to pointers and a seperate size parameter
// Another option would be to use std::array<type_t,N>&, but this syntax for passing arrays
// is very useful knowledge.
//
// constexpr means, if you follow some rules you can use this function at compile time
// which means that the compiler will compile this function and then use it too
//
// auto return type means that you let the compiler work out what type you return
// this can help later when refactoring code.
//
template<typename type_t, std::size_t N>
constexpr auto add(const type_t(&arr1)[N], const type_t(&arr2)[N])
{
// You can't return "C" style arrays from functions but you can return objects.
// std::array is a wrapper object for arrays (with almost no overhead)
// the extra {} at the end will initialize all values in the array to default value for type_t (0 for ints)
// (one of the rules for constexpr, everything must be initialized)
std::array<type_t, N> retval{};
// a standard for loop
for (std::size_t n = 0; n < N; ++n) retval[n] = arr1[n] + arr2[n];
// return the array, since we return a std::array<type_t,N> that will also
// become the return type of the function (auto)
return retval;
}
int main()
{
// constexpr initialization allows these arrays to be used at compile time.
constexpr int arr[] = { 1, 2, 3 };
constexpr int arr2[] = { 7, 4, 6 };
// with constexpr ask the compiler to run add at compile time
// (if the rules for constepxr in add do not fully apply then
// the code will still be executed at runtime)
constexpr auto result = add(arr, arr2);
// static_assert, is like assert but then evaluated at compile time.
// if the assert fails then teh code will not compile.
static_assert(result[0] == 8);
static_assert(result[1] == 6);
static_assert(result[2] == 9);
// to show you can use the results at runtime too
bool comma{ false };
// this is a range based for loop
// using range based for loops ensures you never run out of the
// bounds of an array (reduces bugs)
//
// const auto &
// When looping over all the elements of the array
// value will be a const reference to the current element
// visited.
// a reference to avoid copying data (not so important for ints, but important for
// more complex datatypes)
// const because we are only using it, not modifying it.
for (const auto& value : result)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
return 0;
}
You're going to want another array to store your values, we'll call this arr3 and make it the same size as the other arrays.
int arr[] = { 1,2,3 };
int arr2[] = { 7,4,6 };
int arr3[3]{};
Then you're going to want to add values from arr and arr2 and put them in arr3
arr3[0] = arr[0] + arr2[0];
arr3[1] = arr[1] + arr2[1];
arr3[2] = arr[2] + arr2[2];
You could also do this easily with a loop.
for (int i = 0; i < 3; i++)
{
arr3[i] = arr[i] + arr2[i];
}
As you get more involved with vectors and matrices, you might want to consider using a proper algebra library like Armadillo. On Ubuntu you would just add
apt get install libarmadillo-dev
Then on your CMakeLists.txt
project(arma)
cmake_minimum_required( VERSION 3.0 )
find_package( Armadillo REQUIRED )
include_directories( ${ARMADILLO_INCLUDE_DIR} )
add_executable( testarma testarma.cpp )
And use it on your code
#include <armadillo>
#include <iostream>
int main()
{
using vec = arma::Mat<int>;
vec A{1, 2, 3};
vec B{4, 5, 6};
vec C = A + B;
std::cout << C << std::endl;
}
$ ./testarma
5 7 9

How can I rotate a particular subset of a vector?

I want to rotate a subset of an vector inside the whole vector. The subset to be rotated is defined by another vector.
What I want to achieve is this:
template<typename CONTAINER>
void rotateSubset(CONTAINER& whole, const CONTAINER& subset)
{
// ???
}
auto whole = std::vector<int> {1, 2, 3, 4, 5};
auto part = std::vector<int> { 2, 3, 4 };
auto part2 = std::vector<int> {1, 5};
rotateSubset(whole, part);
// whole is now 1, 3, 4, 2, 5;
rotateSubset(whole, part2);
// whole is now 5, 3, 4, 2, 1
The given subset is guaranteed to be contained by the larger whole set. The subset could be any subset of the whole, in any order; it need not be contiguous.
This is what I've tried so far:
template<typename CONTAINER>
void rotateSubset(CONTAINER& whole, const CONTAINER& subset)
{
assert(subset.isSubsetOf(whole)); // don't worry about the implementation of this pseudo-code for now
std::rotate(subset.begin(), subset.end());
if (subset.size() == whole.size())
whole = subset;
else
{
// copy the subset vector into the whole vector in the new order
auto it = subset.cbegin();
for (auto& element : whole)
if (std::find(subset.cbegin(), subset.cend(), element) != subset.cend())
element = *it++;
}
}
This works, however it feels a bit sketchy to me. I was wondering if there was some neat way of using the Ranges library in C++20 to do it. Something like this:
// PSEUDO-CODE
auto subRange = std::ranges::views::subset(whole, part);
std::rotate(subRange.begin(), subRange.end());
I don't have a good knowledge of the Ranges library yet, but I think that something like this should be possible.
Please note: I want the solution to use a simple std::rotate() at some level. The reason for this is that I want to perform other similar functions on a sub-set as well (i.e. std::shuffle()), so the actual function that does the rotation / shuffling / whatever will be a variable in the final version. It's the "altering a subset" part that I'm really interested in here; the rest will come together later.

How to replicate map, filter and reduce behaviors in C++ using STL?

I suppose we can use std::transform to replicate the map behavior in C++ like this :
std::vector<int> in = { 1 , 2 , 3 ,4 };
std::vector<int> out(in.size());
std::transform(in.being() , in.end() , out.begin() , [](const int & val)
{
return val+1;
});
I guess a better way would be to use the back inserter.'
std::vector<int> out2;
std::transform(in.begin() , in.end() , std::back_inserter(out2) , [](const int & val){
return val + 1;
});
// out will be { 2 , 3 ,4 ,5 }
Am I right ? How do I do the filter and reduce operations in C++ using STL ?
You can use std::transform to do mapping, and std::copy_if for filtering.
You have two options for reduce depending on your input and if you want to use a specific type of execution model. I've written some simple examples below to demonstrate common use cases. Note that there are multiple overloads for all these algorithms that you should use depending on your needs.
std::transform
Squaring a vector of integers in place:
std::vector<int> nums{1,2,3,4};
auto unary_op = [](int num) {return std::pow(num, 2);};
std::transform(nums.begin(), nums.end(), nums.begin(), unary_op);
// nums: 1, 4, 9, 16
std::copy_if
Filtering odd numbers only from a vector of integers:
std::vector<int> nums{1,2,3,4};
std::vector<int> odd_nums;
auto pred = [](int num) {return num & 1;};
std::copy_if(nums.begin(), nums.end(), std::back_inserter(odd_nums), pred);
// odd_nums: 1, 3
std::reduce
Sum of integers in the vector starting from 0 using parallel execution model. This is really useful if, for example, you are doing a reduce operation on a really big list. Reckon that the binary operator in this case ("+") is associate and commutative, otherwise the behavior would've been non-deterministic. This is really important. The reduce operation is out-of-order if the execution model is not sequential. Only available since C++17.
std::vector<int> nums{1,2,3,4};
auto binary_op = [](int num1, int num2){return num1 + num2;};
int result = std::reduce(std::execution::par, nums.begin(), nums.end(), 0, binary_op);
// result: 10
std::accumulate
Same as reduce except it doesn't support execution model and the reduce operation is done in-order.
std::vector<int> nums{1,2,3,4};
auto binary_op = [](int num1, int num2){return num1 + num2;};
int result = std::accumulate(nums.begin(), nums.end(), 0, binary_op);
// result: 10
Depends which container you use.
std::back_inserter will work only if the container has a push_back function.
For example back_insterter can't be used with forward_list.
In that case we need to have the memory allocated before we call std::transform on the same and first approach is better.
I generalized the transform example from happy_sisyphus's answer into a function:
#include <algorithm>
// avoid calling this function 'map', it will clash with 'using std::map;'
template<typename I, typename F>
void apply_to_all(I& iterable, const F& functor)
{
std::transform(iterable.begin(), iterable.end(), iterable.begin(), functor);
}
Example use:
std::vector<int> nums{1,2,3,4};
auto unary_op = [](int num) {return std::pow(num, 2);};
apply_to_all(nums, unary_op);
// nums: 1, 4, 9, 16

Is there a simple way to convert a 2D/multidimensional array to a vector in c++? [duplicate]

What is the simplest way to convert array to vector?
void test(vector<int> _array)
{
...
}
int x[3]={1, 2, 3};
test(x); // Syntax error.
I want to convert x from int array to vector in simplest way.
Use the vector constructor that takes two iterators, note that pointers are valid iterators, and use the implicit conversion from arrays to pointers:
int x[3] = {1, 2, 3};
std::vector<int> v(x, x + sizeof x / sizeof x[0]);
test(v);
or
test(std::vector<int>(x, x + sizeof x / sizeof x[0]));
where sizeof x / sizeof x[0] is obviously 3 in this context; it's the generic way of getting the number of elements in an array. Note that x + sizeof x / sizeof x[0] points one element beyond the last element.
Personally, I quite like the C++2011 approach because it neither requires you to use sizeof() nor to remember adjusting the array bounds if you ever change the array bounds (and you can define the relevant function in C++2003 if you want, too):
#include <iterator>
#include <vector>
int x[] = { 1, 2, 3, 4, 5 };
std::vector<int> v(std::begin(x), std::end(x));
Obviously, with C++2011 you might want to use initializer lists anyway:
std::vector<int> v({ 1, 2, 3, 4, 5 });
Pointers can be used like any other iterators:
int x[3] = {1, 2, 3};
std::vector<int> v(x, x + 3);
test(v)
You're asking the wrong question here - instead of forcing everything into a vector ask how you can convert test to work with iterators instead of a specific container. You can provide an overload too in order to retain compatibility (and handle other containers at the same time for free):
void test(const std::vector<int>& in) {
// Iterate over vector and do whatever
}
becomes:
template <typename Iterator>
void test(Iterator begin, const Iterator end) {
// Iterate over range and do whatever
}
template <typename Container>
void test(const Container& in) {
test(std::begin(in), std::end(in));
}
Which lets you do:
int x[3]={1, 2, 3};
test(x); // Now correct
(Ideone demo)
One simple way can be the use of assign() function that is pre-defined in vector class.
e.g.
array[5]={1,2,3,4,5};
vector<int> v;
v.assign(array, array+5); // 5 is size of array.
One way can be to use the array's bound in one go like this:
int a[3] = {1, 2, 3};
vector<int> v(a, *(&a+1));