Exercise: The vector A[1 to N] and a value s is given. Build the program that writes backwards every group of s elements. If s divided by N has a remainder, then the remaining values should be unchanged. If s is bigger than N (the nr of elements of the vector) than there will be no modification.
Lets say s = 4 and A = (1, 2, 3, 4, 5, 6, 7, 8)then after execution the values will be A = (4, 3, 2, 1, 8, 7, 6, 5)
My teacher requires this kind of vector: int n, A[n] where n is a value given by the user. And i think this is what is causing my program to crash when i read the final values. If not, where is the problem?
#include <iomanip>
using namespace std;
int ordering(int s, int n, int A[]);
int main()
{
int n, A[n];
int s;
cout << "Vlera e s: ";
cin >> s;
if (s <= 0)
{
return 1;
}
cout << "\nN: ";
cin >> n;
if (n <= 0)
{
return 1;
}
cout << "\nVector:";
for (int i = 0; i < n; i++)
{
A[i] = i + 1;
cout << " " << A[i] << " ";
}
if (s > n)
{
cout << "\nNo change\n";
return 0;
}
else
{
ordering(s, n, A);
}
cout << "\nNew vector:";
for (int i = 0; i < n; i++)
{
cout << " " << A[i] << " ";
}
return 0;
}
int ordering(int s, int n, int A[])
{
int counter = 0;
for (int i = 0, divider = n / s; i < divider; i++)
{
int decrease = 0;
for (int j = counter, a = counter + s; j < a; j++)
{
A[j] = a - decrease;
decrease++;
}
counter += s;
}
return 0;
}
This program using a compiler extension to allow variable sized arrays in the form myArray[variableSize]. Whilst not standard, it does work on some compilers.
You are using this feature here:
int n, A[n];
However, n is uninitialised at this point. This is undefined behaviour even on the compilers that support such variable sized arrays. One possible (but not the only) outcome of undefined behaviour is your program crashing.
Undefined behaviour can do anything in theory, but the realistic set of things in can do in reality is smaller. Some of the likely implications of the undefined behaviour here:
n has some huge number in it, from whatever last used that bit of memory. As a result, A is huge.
n is 0. You can't have a 0 sized array. If the compiler doesn't notice this, you could end up trashing memory.
Since n is uninitialised, the optimiser for the compiler (they usually do very some optimisations, even when on -O0) assumes that undefined behaviour cannot occur, which is violated here, leading to strange behaviour.
n is a reasonable value, just by luck, but because it is later updated it no longer matches the size of the array and you end up reading / writing memory off the end of the array, trashing memory.
There are other possibilities, but this gives an idea of the kind of things that can happen as a result of this specific instance of undefined behaviour. If you're interested to know more, using a debugger to step through the code in assembly (you only need learn a little to understand the output, it looks more scary than it need be) will show you what's actually happening.
Variable length arrays is not a standard C++ feature.
int n, A[n];
Moreover in the above declaration the variable n was not initialized. So in any case the program has undefined behavior.
Instead of an array you could use the standard class template std::vector.
The program can look simpler and more safer is to use standard algorithms such as, for example, std::reverse.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <numeric>
void reorder( std::vector<int> &v, size_t s )
{
if ( not ( s < 2 ) )
{
for ( auto last = std::end( v );
not (std::distance( std::begin( v ), last ) < s ); )
{
auto first = std::prev( last, s );
std::reverse( first, last );
last = first;
}
}
}
int main()
{
std::cout << "Vlera e s: ";
size_t s = 0;
std::cin >> s;
std::cout << "N: ";
size_t n = 0;
std::cin >> n;
std::vector<int> v( n );
std::iota( std::begin( v ), std::end( v ), 1 );
putchar( '\n' );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
reorder( v, s );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
The program output might look like
Vlera e s: 4
N: 10
1 2 3 4 5 6 7 8 9 10
1 2 6 5 4 3 10 9 8 7
But it seems you need write the corresponding code yourself using loops. In this case the program can look like
#include <iostream>
#include <vector>
void reorder( std::vector<int> &v, size_t s )
{
if ( not ( s < 2 ) )
{
for ( auto n = v.size(); !( n < s ); n -= s )
{
for ( size_t i = 0; i < s / 2; i++ )
{
int value = v[n - s + i];
v[n - s + i] = v[n - i - 1];
v[n - i - 1] = value;
}
}
}
}
int main()
{
std::cout << "Vlera e s: ";
size_t s = 0;
std::cin >> s;
std::cout << "N: ";
size_t n = 0;
std::cin >> n;
std::vector<int> v( n );
int value = 1;
for ( auto &item : v ) item = value++;
putchar( '\n' );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
reorder( v, s );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
The program output might look as already shown above
Vlera e s: 4
N: 10
1 2 3 4 5 6 7 8 9 10
1 2 6 5 4 3 10 9 8 7
Passing variable as array size is not valid you need to use constant const int n or create dinamic array int* arr = new int[n];, that array will be created in runtime, and you can pass variable as it size. Dont forget to delete that array whet it goes out of scope delete[] arr;
Related
For my 2d array in C++, the 2d array needs to be flipped at a certain position. I have to write a function that flips the array
Foe instance,
Before:
double A[][2] = {{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}}
A B C D
call function invert(or flip): invert(A, 8, 3, 4);
after:
double A[][2] = { {0, 0}, {1, 1}, {2, 2},{6, 6}, {5, 5}, {4, 4}, {3, 3}, {7, 7}}
D C B A
Here is the attempt I have tried
#param A is the list of locations (x,y) of the cities in the current tour.
#param n is the number of cities in A.
#param start is the index of the beginning of the section to be inverted.
#param len is the length of the segment to invert(or flip).
void invert ( double A[][2], int n, int start, int len ) {
int(*tmp)[2] = new int[][2];
for(int i = 0; i >= A.length; i--){
for(int j = 0; j >= A[i].length; j--){
if( i > start)
tmp = A[i][j];
}
}
for(i = start; i < A.length; i++)
for(j = start; j < A[i].length; j++){
while (i <= end){
tmp = A[i][j];
}
}
}
The errors I have are
expressions must have class type
a value of type double cannot be assigned to an entity of type "double(*)[2]
cannot determine which instance of overload function "end" is intended
I am fully aware that most of the errors in my code are evident to find, but I needed to start somewhere.
I admit, I don't know how to do it with a 2D C-array. I can only tell you about the simple way to do it.
First, a general advice: Name your stuff. What if I had to read only your code to see that you are dealing with locations of cities, that have x and y coordinates, instead of having to read your text, wouldn't that be great?
Next, for resizable arrays, you can (/should) use std::vector instead of C-arrays. C-arrays decay to pointers when passed to functions. C-arrays have their size as part of their type, but it is inconvenient to access it (and impossible once decayed to a pointer). And manually resizing dynamic C-arrays isn't much fun either.
Eventually, the "simple way" is to use an existing algorithm. To reverse elements in a range it is std::reverse:
#include <iostream>
#include <vector>
#include <algorithm>
struct location {
int x;
int y;
};
int main() {
std::vector<location> cities{{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}};
for (const auto& loc : cities){
std::cout << loc.x << " " << loc.y << "\n";
}
std::cout << "\n";
std::reverse(cities.begin()+ 3,cities.begin() + 7);
for (const auto& loc : cities){
std::cout << loc.x << " " << loc.y << "\n";
}
}
Output:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
0 0
1 1
2 2
6 6
5 5
4 4
3 3
7 7
Actually with a 1-D c-array it is almost the same. The major difference is that c-arrays do not have begin as member. This produces same output as above:
location cities2[] = {{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}};
for (const auto& loc : cities2){
std::cout << loc.x << " " << loc.y << "\n";
}
std::cout << "\n";
std::reverse(std::begin(cities2)+ 3,std::begin(cities2) + 7);
for (const auto& loc : cities2){
std::cout << loc.x << " " << loc.y << "\n";
}
And if you want to wrap it in a function you need to take care of the array decaying to a pointer:
void my_reverse(location* loc, size_t len, size_t first, size_t last){
std::reverse(loc + first, loc + last + 1);
}
(I choose last to be the last element to be reversed. Note that the algorithm takes an iterator to the element one past the last element to be reversed).
Complete example with all three variants: https://godbolt.org/z/WMdea7WP3
That's how I'd write the function if I knew it would always be used with 2 column arrays
void invert(double cities[][2], int size, int start, int len) {
if (size < 0 || len < 0)
return;
double tempCoordsX, tempCoordsY;
int endPos = start + len - 1;
for (int i = start; i < (start + len/2); i++) {
int mirroredPos = (endPos - (i - start)) % size;
tempCoordsX = cities[i][0];
tempCoordsY = cities[i][1];
cities[i][0] = cities[mirroredPos][0];
cities[i][1] = cities[mirroredPos][1];
cities[mirroredPos][0] = tempCoordsX;
cities[mirroredPos][1] = tempCoordsY;
}
}
I repeat: please name your stuff
I'm a beginner in C++ and meet a problem.
Assuming there is a vector of integers, how could we get the index array for the same value?
i.e. If the vector is: [a,a,b,c,a,c,b,c] where a, b, c are integers.
Then the expected index arrays should be:
v_a = [1,2,5], v_b = [3,7], v_c = [4,6,8]
Is there any simple way in C++ to implement this?
In my opinion it is better to use std::multimap in this case because the number of different integers in the original array is unknown and as I understand can be changed.
Here is a demonstrative program
#include <iostream>
#include <vector>
#include <map>
int main( void )
{
std::vector<char> v = { 'a', 'a', 'b', 'c', 'a', 'c', 'b', 'c' };
std::multimap<char, size_t> m;
for ( size_t i = 0; i < v.size(); i++ ) m.insert( { v[i], i } );
for ( auto it = m.begin(); it != m.end(); )
{
auto p = m.equal_range( it->first );
while ( p.first != p.second )
{
std::cout << p.first++->second << ' ';
}
std::cout << std::endl;
it = p.second;
}
}
The program output is
0 1 4
2 6
3 5 7
Take into account that array indices start from 0 in C++.
First you need to take in account that in C++ (as in C and Java and many others languages), array's and vector's indexes start at 0. N size means N - 1 positions. For example: one vector/array with 3 elements, goes from index 0 to index 2.
In your example: v_a = [0,1,4], v_b = [2,6], v_c = [3,5,7]
int a, b, c;
vector<int> integers;
vector<int> v_a;
vector<int> v_b;
vector<int> v_c;
void indexes(){
for(int i = 0; i < integers.size(); i++){
if( integers[i] == a )
v_a.push_back(i);
else if( integers[i] == b )
v_b.push_back(i);
else if( integers[i] == c )
v_c.push_back(i);
}
}
Well this is the solution for your problem. Since you're learning C++, you may want to take this solution and try to make it more generic.
I am trying to make a program for pascal's triangle,the formaula to calculate the rth value in nth row is n!/r!(n-r)!
I've been tring to implement it like this:
#include <iostream> // std::cout, std::endl
#include <iomanip> // std::setw
int Pascal(int ,int );
int Factorial( int);
int main ()
{
int n=0;//Number of rows in the triangle
for(int i=12;i>0;i--)
{
std::cout << std::setw(i)<<std::endl;
for (int j=1;j<12-i;j++)
{
int r=0; //rth element initialized for each row
int P= Pascal(r,n);
std::cout << P ;
std::cout <<std::setw(2);
r=r+1;
}
n=n+1;
}
std::cout<<std::endl;
return 0;
}
int Pascal(int r,int n)
{
int d = n-r; ///Difference of n with r
int f1; ///factorial of n
int f2; ///factorial of r
int f3; ///factorial of (n-r)
f1=Factorial(n);
f2=Factorial(r);
f3=Factorial(d);
return f1/(f2*f3);
}
int Factorial( int begin )
{
int F;
if ( begin == 0 )
{
return 1;
}
else
{
F= begin*Factorial(begin-1);
}
return F;
}
but somehow I am getting this output:
1
1 1
1 1 1
1 1 1 1
1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 112
Could someone guide me where am I going wrong?
Your first, obvious problem is of course that you should be printing Pascal(i,j). Your second is more subtle:
Recursion
The whole point of Pascal's Triangle is that it gives a way of computing binomial coefficients without needing to compute the factorials.
The problem is factorials grow really quickly and a coefficient such as Pascal(1,120) = 120!/(1!*119!}, is equal only to 120, but its nominator and denominator are on the order of 10^198 which could not be stored in any machine integer type.
Check out Pascal's Triangle on Wikipedia. The whole point is the recursive relation:
Pascal( r, n ) = Pascal( r-1, n-1 ) + Pascal( r, n-1 )
Here's a simple solution making use of that (this only prints the r,n pascal number):
#include <iostream>
#include <sstream>
int pascal( int r, int n ) {
if( n == 0 )
return 1;
if( r == 0 || r == n )
return 1;
return pascal( r - 1, n - 1 ) + pascal( r, n - 1 );
}
int main( int argc, char *argv[] ) {
if( argc != 3 ) {
std::cout << "Expected exactly 3 arguments." << std::endl;
return -1;
}
int r, n;
std::stringstream ss;
ss << argv[1] << ' ' << argv[2];
ss >> r >> n;
if( ss.bad() || r < 0 || n < 0 || r > n ) {
std::cout << "Invalid argument values." << std::endl;
return -2;
}
std::cout << pascal( r, n ) << std::endl;
return 0;
}
Memoization
There is a third and even more subtle problem with this method, its complexity is much worse than it needs to be. Think about computing Pascal(3,6):
Pascal(3,6) =
= Pascal(2,5) + Pascal(3,5) =
= (Pascal(1,4)+Pascal(2,4)) + (Pascal(2,4)+Pascal(3,4)) = ...
In that last line you'll notice Pascal(2,4) appears twice which means your code will compute it twice. Futhermore Pascal( 3, 5 ) is actually equal to Pascal(2,5). So your could is computing Pascal(2,5) twice, which means computing Pascal(2,4) four times. This means as r and n grow large the program will be very slow. We would like to compute each Pascal(i,j) a single time and then save its value to be used by other calls. To do this, a simple way is to use a map which maps (r,n) pairs to Pascal(r,n) values: std::map< std::pair, int >. This method is called memoization. Also, changing ints to long long for big numbers, you get the following algorithm:
#include <iostream>
#include <sstream>
#include <map>
typedef long long Integer;
typedef std::map< std::pair< Integer, Integer >, Integer > MemoMap;
typedef MemoMap::iterator MemoIter;
MemoMap memo;
Integer pascal( Integer r, Integer n ) {
// make sure r <= n/2 using the fact that pascal(r,n)==pascal(n-r,n)
if( r > n / 2LL )
r = n - r;
// base cases
if( n == 0LL || r == 0LL )
return 1LL;
// search our map for a precalculated value of pascal(r,n)
MemoIter miter = memo.find( std::make_pair( r, n ) );
// if it exists return the precalculated value
if( miter != memo.end() )
return miter->second;
// otherwise run our function as before
Integer result = pascal( r - 1LL, n - 1LL ) + pascal( r, n - 1LL );
// save the value and return it
memo.insert( std::make_pair( std::make_pair( r, n ), result ) );
return result;
}
int main( int argc, char *argv[] ) {
if( argc != 3 ) {
std::cout << "Expected exactly 3 arguments." << std::endl;
return -1;
}
Integer r, n;
std::stringstream ss;
ss << argv[ 1 ] << ' ' << argv[ 2 ];
ss >> r >> n;
if( ss.bad() || r < 0LL || n < 0LL || r > n ) {
std::cout << "Invalid argument values." << std::endl;
return -2;
}
std::cout << pascal( r, n ) << std::endl;
return 0;
}
Before, Pascal(5,100) would never terminate. Now it finishes instantly on my computer. Integrate this code into yours and you'll be a happy panda.
Bottom-up
Memoization is top-down dynamic programming i.e. you first think of the hardest problem and then divide it into simpler, overlapping problems while saving the results along the way. A bottom up solution would start with the first row of the Pascal Triangle and keep computing following rows - this is more efficient, both in speed and memory (storing only two arrays).
The top-down method however is easier to implement (you don't have to think about what values you're going to need you just save everything) and it allows you to save intermediate results between independent pascal() calls. In your case, since you're trying to print Pascal's Triangle by calling pascal independently many times, this is the appropriate method. If you print and compute at the same time, bottom up is by far the most efficient way of doing it:
#include <iostream>
#include <sstream>
#include <vector>
typedef long long Integer;
void print_pascal( Integer maxn ) {
std::vector< Integer > prevRow, currentRow;
prevRow.resize( maxn + 1 );
currentRow.resize( maxn + 1);
prevRow[ 0 ] = 1;
// print first row.
std::cout << 1 << std::endl;
for( Integer currentN = 1 ; currentN <= maxn ; ++ currentN ) {
// compute & print current row
currentRow[ 0 ] = currentRow[ currentN ] = 1;
std::cout << 1;
for( Integer r = 1 ; r < currentN ; ++ r ) {
currentRow[ r ] = prevRow[ r - 1 ] + prevRow[ r ];
std::cout << ' ' << currentRow[ r ];
}
std::cout << ' ' << 1 << std::endl;
// constant time because swap() only swaps internal ptrs.
currentRow.swap( prevRow );
}
}
int main( int argc, char *argv[] ) {
if( argc != 2 ) {
std::cout << "Expected exactly 1 argument." << std::endl;
return -1;
}
Integer maxn;
std::stringstream ss;
ss << argv[ 1 ]; ss >> maxn;
if( ss.bad() || maxn < 0LL ) {
std::cout << "Invalid argument values." << std::endl;
return -2;
}
print_pascal( maxn );
return 0;
}
The very first thing you've gone wrong at is the formatting of your code. It's horrible. (Sorry, it really is.)
The second thing is that you are always printing Pascal(r, n) whereas they are constant 0, 0 - you should print Pascal(i, j) instead, since i and j are the loop counters.
By the way, you'd be better off calculating the factorials iteratively and using long enough integers, your code threw SIGXCPU on IDEOne and segfaulted on my computer.
I have 3-column integer arrays, whose last 2 elements are for sorting. For example
10 0 1
11 0 2
12 1 2
13 0 1
I want them to become:
10 0 1
13 0 1
11 0 2
12 1 2
The arrays are first sorted according to the 2nd column, and then again according to 3rd column.
I have over 3000 rows, so I need something also fast. How can you do this in c++?
Note: The array will be allocated dynamically using the following templates:
template <typename T>
T **AllocateDynamic2DArray(int nRows, int nCols){
T **dynamicArray;
dynamicArray = new T*[nRows];
for( int i = 0 ; i < nRows ; i++ ){
dynamicArray[i] = new T[nCols];
for ( int j=0; j<nCols;j++){
dynamicArray[i][j]= 0;
}
}
return dynamicArray;
}
in main,
int ** lineFilter = AllocateDynamic2DArray(2*numberOfLines,3);
you can use std::sort(); however, this is complicated by your array being 2D.
In general, std::sort() can't eat 2D arrays; you have to create a class to cast around the compiler warnings and complaints:
#include <iostream>
#include <algorithm>
int data[4][3] = {
{10,0,1},
{11,0,2},
{12,1,2},
{13,0,1}
};
struct row_t { // our type alias for sorting; we know this is compatible with the rows in data
int data[3];
bool operator<(const row_t& rhs) const {
return (data[1]<rhs.data[1]) || ((data[1]==rhs.data[1]) && (data[2]<rhs.data[2]));
}
};
int main() {
std::sort((row_t*)data,(row_t*)(data+4));
for(int i=0; i<4; i++)
std::cout << i << '=' << data[i][0] << ',' << data[i][1] << ',' << data[i][2] << ';' << std::endl;
return 0;
}
It becomes much easier if you use a std::vector to hold your items that really are of type row_t or such. Vectors are dynamically sized and sortable.
I think this should work:
template<typename T>
struct compareRows {
bool operator() (T * const & a, T * const & b) {
if (a[1] == b[1])
return a[2] < b[2];
else
return a[1] < b[1];
}
};
std::sort(dynamicArray, dynamicArray+nrows, compareRows<int>());
Use a functor to implement the comparison between the rows. The sort will take pointers to the beginning of each row and swap them according to the contents of the rows. The rows will stay in the same places in memory.
OK, the OP has a three-column integer arrays, which is not straightforward to sort, because you can't assign arrays.
One option is to have arrays of structs, where the struct contains one element for each column, write a custom compare routine and use std::sort.
Another option is to pretend we have such an array of structs and employ the evilness of reinterpret_cast, like below:
#include <algorithm>
#include <iostream>
struct elt_t
{
int e0;
int e1;
int e2;
};
int
compare (const elt_t &a, const elt_t &b)
{
if (a.e1 == b.e1)
return a.e2 < b.e2;
else
return a.e1 < b.e1;
}
int a [10][3] =
{
{ 10, 0, 1 },
{ 11, 0, 2 },
{ 12, 1, 2 },
{ 13, 0, 1 }
};
int
main ()
{
std::sort (reinterpret_cast<elt_t *>(&a[0]),
reinterpret_cast<elt_t *>(&a[4]), compare);
int i, j;
for (i = 0; i < 4; ++i)
std::cout << a [i][0] << ", " << a [i][1] << ", " << a [i][2] << std::endl;
return 0;
}
Of course, whether or not this is standards compliant is highly debatable :)
EDIT:
With the added requirement for the matrix to by dynamically allocated, you can use an array of std::vector, or a vector of std::vector:
#include <algorithm>
#include <iostream>
#include <vector>
int
compare (const std::vector<int> &a, const std::vector<int> &b)
{
if (a[1] == b[1])
return a[2] < b[2];
else
return a[1] < b[1];
}
std::vector<int> *
make_vec (unsigned int r, unsigned int c)
{
std::vector<int> *v = new std::vector<int> [r];
/* Don't care for column count for the purposes of the example. */
v [0].push_back (10); v [0].push_back (0); v [0].push_back (1);
v [1].push_back (11); v [1].push_back (0); v [1].push_back (2);
v [2].push_back (12); v [2].push_back (1); v [2].push_back (2);
v [3].push_back (13); v [3].push_back (0); v [3].push_back (1);
return v;
}
int
main ()
{
std::vector<int> *v = make_vec (4, 3);
std::sort (&v[0], &v[4], compare);
int i, j;
for (i = 0; i < 4; ++i)
std::cout << v[i][0] << ", " << v [i][1] << ", " << v [i][2] << std::endl;
delete [] v;
return 0;
}
use this for the second column and then for the third. Now it works for single dim arrays
int *toplace(int *start, int *end)
{
int *i = start+1, *j= end-1;
while(i<=j)
{
while(*i<=*start && i<=j) {i++;}
while(*j>=*start && i<=j) {j--;}
if (i<j) std::swap(*i++,*j--);
}
std::swap(*start,*(i-1));
return i-1;
}
void quicksort(int *start, int *end)
{
if (start >= end) return;
int *temp = start;
temp = toplace(start,end);
quicksort(start,temp);
quicksort(temp+1,end);
}
You can do this using the bubble sort algorithm (http://en.wikipedia.org/wiki/Bubble_sort)
Basically iterate through all records, comparing the current record, with the next. If the current record's 2nd column is higher then swap these records. If the current record's 2nd column is equal but the 3rd column is higher, then swap also.
Continue iterating until no more swaps are made.
To use your example:
10 0 1
11 0 2
12 1 2 (swap with next)
13 0 1
10 0 1
11 0 2(swap with next)
13 0 1
12 1 2
10 0 1
13 0 1
11 0 2
12 1 2
And done!
I have a std::vector. I want to create iterators representing a slice of that vector. How do I do it? In pseudo C++:
class InterestingType;
void doSomething(slice& s) {
for (slice::iterator i = s.begin(); i != s.end(); ++i) {
std::cout << *i << endl;
}
}
int main() {
std::vector v();
for (int i= 0; i < 10; ++i) { v.push_back(i); }
slice slice1 = slice(v, 1, 5);
slice slice2 = slice(v, 2, 4);
doSomething(slice1);
doSomething(slice2);
return 0;
}
I would prefer not to have to copy the elements to a new datastructure.
You'd just use a pair of iterators:
typedef std::vector<int>::iterator vec_iter;
void doSomething(vec_iter first, vec_iter last) {
for (vec_iter cur = first; cur != last; ++cur) {
std::cout << *cur << endl;
}
}
int main() {
std::vector v();
for (int i= 0; i < 10; ++i) { v.push_back(i); }
doSomething(v.begin() + 1, v.begin() + 5);
doSomething(v.begin() + 2, v.begin() + 4);
return 0;
}
Alternatively, the Boost.Range library should allow you to represent iterator pairs as a single object, but the above is the canonical way to do it.
I learnt Python before I learnt C++. I wondered if C++ offered slicing of vectors like slicing in Python lists. Took a couple of minutes to write this function that allows you to slice a vector analogous to the way its done in Python.
vector<int> slice(const vector<int>& v, int start=0, int end=-1) {
int oldlen = v.size();
int newlen;
if (end == -1 or end >= oldlen){
newlen = oldlen-start;
} else {
newlen = end-start;
}
vector<int> nv(newlen);
for (int i=0; i<newlen; i++) {
nv[i] = v[start+i];
}
return nv;
}
Usage:
vector<int> newvector = slice(vector_variable, start_index, end_index);
The start_index element will be included in the slice, whereas the end_index will not be included.
Example:
For a vector v1 like {1,3,5,7,9}
slice(v1,2,4) returns {5,7}
Taken from here:
std::vector<myvector::value_type>(myvector.begin()+start, myvector.begin()+end).swap(myvector);
Usage example:
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> indexes{3, 6, 9};
for( auto index : indexes )
{
int slice = 3;
std::vector<int> bar{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int>( bar.begin() + index - slice, bar.begin() + index ).swap(bar);
std::cout << "bar index " << index << " contains:";
for (unsigned i=0; i<bar.size(); i++)
std::cout << ' ' << bar[i];
std::cout << '\n';
}
return 0;
}
Outputs:
bar index 3 contains: 1 2 3
bar index 6 contains: 4 5 6
bar index 9 contains: 7 8 9
As others have said, you can represent the "slice" as pair of iterators. If you are willing to use Boost, you can use the range concept. Then you will have even begin()/end() member functions available and the whole thing looks a lot like a container.
use boost range adapters. they are lazy:
operator|() is used to add new behaviour lazily and never modifies its
left argument.
boost::for_each(v|sliced(1,5)|transformed(doSomething));
doSomething needs to take range as input. a simple (may be lambda) wrapper would fix that.
You can represent those "slices" with a pair of iterators.
You don't need a pair of iterators to slice a vector. Three indexes will do because it allows you to create slices with steps:
static const int arr[] = {16,2,77,29,42};
vector<int> v (arr, arr + sizeof(arr) / sizeof(arr[0]) );
vector<int>::iterator i;
const int step = 2;
const int first = 0;
const int last = v.size()-1;
int counter=first;
for (i = v.begin()+first; counter<last; i+=step, counter+=step) {
// Do something with *i
cout << *i << endl;
}
Prints:
16
77
In this code, a counter is needed to track the position because not all iterators can do this.
It is possible to use slices with std::valarray. Which is an STL analogue of numpy.array in python. It support different vectorized operations like min, max, +,-, *, /, etc.
More info here.
std::slice(start, length, stride) allows to select and modify slices of an array without copying (documentation here).
The slicing would look like this:
std::valarray<int> foo (9);
for (int i=0; i<9; ++i) foo[i]=i; // 0 1 2 3 4 5 6 7 8
// | | | | |
std::slice myslice=std::slice(1,5,1); // v v v v v
foo[myslice] *= std::valarray<int>(10,3); // 0 10 20 30 40 50 6 7 8
Or with stride=2:
std::valarray<int> foo (9);
for (int i=0; i<9; ++i) foo[i]=i; // 0 1 2 3 4 5 6 7 8
// | | |
std::slice myslice=std::slice(1,3,2); // v v v
foo[myslice] *= std::valarray<int>(10,3); // 0 10 2 30 4 50 6 7 8
// | | |
foo[std::slice (0,3,3)] = 99; // v v v
// 99 10 2 99 4 50 99 7 8
std::cout << "foo:";
for (std::size_t n=0; n<foo.size(); n++)
std::cout << ' ' << foo[n];
std::cout << '\n';