How can I rotate a particular subset of a vector? - c++

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.

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.

referencing a global vector by a different name within a function

suppose you have three global vectors V1, V2, and V3.
suppose you have a function which performs a set of actions, such as VN[3]++, on one of the above vectors determined by an int value.
in python i would do something like:
global:
v1 = [1,2,3]
v2 = [1,2,3]
v3 = [1,2,3]
lists = [v1, v2, v3]
def function (determiner):
list = lists[determiner]
list[1] += 1...
I think in theory i could just have separate ifs for each possible value of determiner, but it seems like bad code to repeat a length of code multiple times.
(1) What is the correct way to approach this problem? I assume I would use pointers, but I've just learned about them today and i've been struggling to get my code to work. Here's a sample of the code i've been trying.
vector <int> counts0;
vector <int> counts1;
void editor(int determiner){
if (determiner == 1) {
vector<int> & count_l = counts1;
}
else if (determiner = 2) {
vector<int> & count_l = counts2;
}
count_l[5]++;
}
There are two ways to achieve this, depending on what you expect. If lists should reference the vectors, use pointers (as you said, just remember to dereference before indexing)
std::vector<int> a, b, c;
std::vector<std::vector<int>*> lists = {&a, &b, &c};
void editor(int determiner)
{
(*lists[determiner])[5]++;
}
If you want a copy of all vectors in list, don't use pointers (this can be expensive when you modify lists a lot, only use this approach with const data).
std::vector<std::vector<int>> lists = {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}};
void editor(int determiner)
{
lists[determiner][5]++;
}

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));

Check whether an element is in std::initializer_list

I want to be able to write in C++ something similar to the following Python code:
if x in [1, 2, 3, 5] ...
to test whether an element is contained in a set of hard-coded values, defined in-place. Like this:
if (in(x, {1, 2, 3, 5})) ...
Here is the possible implementation of the in function:
template<class T>
bool in(const T& x, std::initializer_list<T> c)
{
return std::find(c.begin(), c.end(), x) != c.end();
}
My question is: do I really have to write this function by myself? Are there any default implementations over there? Maybe in boost? I checked boost::contains, but it works only with strings.
If you have access to c++20 you can use set's contains which returns a bool allowing you to do:
if(set{ 4, 8, 15, 16, 23, 42 }.contains(x))
Live Example
Otherwise, with just c++11 you can still use set's count which only returns 1 or 0 allowing you to do something like:
if(set<int>{ 4, 8, 15, 16, 23, 42 }.count(x) > 0U)
Live Example
Keep in mind that magic numbers can be confusing for your audience (and cause 5 seasons of Lost.)
I'd recommend declaring your numbers as a const initializer_list<int> and giving them a meaningful name:
const auto finalCandidates{ 4, 8, 15, 16, 23, 42 };
if(cend(finalCandidates) != find(cbegin(finalCandidates), cend(finalCandidates), x))
boost::algorithm::contains doesn't only work on strings, it works on any range, i.e. a sequence that can yield a begin and end iterator. To find a single value use it as follows:
auto l = {1,2,3,4};
auto l1 = {2}; // thing you want to find
if(boost::algorithm::contains(l, l1)) { ... }
You can perform your search using the standard library only, but doing so is quite a bit more verbose. A couple of options are:
using a lambda
if(std::any_of(l.begin(), l.end(),
[](int i){ return i == 2; })) { ... }
using std::bind
using std::placeholders::_1;
if(std::any_of(l.begin(), l.end(),
std::bind(std::equal_to<>(), 2, _1)) { ... }
Live demo
Note that std::equal_to<>() is a C++14-only option. For a C++11 compiler, use std::equal_to<int>().
Indeed the STL does not have a simple std::contains() function. Recently, there was a discussion on reddit about this topic.
Unfortunately, what came out of this is that it is considered harmful to have std::contains(), since it encourages people to write slow algorithms. Think for instance of
if (!std::contains(my_set.begin(), my_set.end(), entry)) {
my_set.insert(entry);
}
This code example essentially searches for the correct position twice: Once in contains, and once to find the insert location.
In my opinion, it would still be very helpful to have std::contains(), but so far no one was convinced yet to write a proposal.
So either use boost (as suggested by other in this thread), or write your own function which you essentially already did :-)

modify every element of collection

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));