Slicing a vector - c++

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

Related

Insert an element in a descending sorted array and keep array sorted

Assuming we have a sorted descending vector, like:
vector<int> array {26,  21,  13,  11,  8,  3,  2}.
I would like to insert a new and different element to the ones already present, so that descending sort of vector is kept.
Example flow:
I want to insert element 22, basically added at index 1, thus vector would be: 26, 22, 21, 13, 11, 8, 3, 2
I want to insert element 17, basically added at index 3, thus vector would be: 26, 22, 21, 17, 13, 11, 8, 3, 2
I want to insert element 1, basically added at a new index, thus vector would be: 26, 22, 21, 17, 13, 11, 8, 3, 2, 1
I want to insert element 43, basically added at index 0, thus vector would be: 43, 26, 22, 21,  17, 13, 11, 8, 3, 2, 1
A fast sample implementation in C++ would be:
#include<iostream>
#include<vector>
#include <chrono>
using namespace std;
using namespace std::chrono;
int get_Index_Insert(const vector<int>& array, int lengthArray, int insertValue)
{
int whereInsert = lengthArray;
for (int i = 0; i < lengthArray; i++)
{
if (array[i] < insertValue)
{
whereInsert = i;
break;
}
}
return whereInsert;
}
int get_Index_Insert2(const vector<int>& array, int lengthArray, int insertValue)
{
int whereInsert = lengthArray;
// Break out early if these cases:
if (lengthArray == 0 || (array[lengthArray - 1] > insertValue))
return whereInsert;
// Otherwise do your binary magic:
int low = 0;
int high = lengthArray - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (array[mid] > insertValue)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
whereInsert = high + 1;
return whereInsert;
}
vector<int> insert_Value(const vector<int>& arrayInput, int insertValue)
{
vector<int> arrayOutput;
int lenghtArray = arrayInput.size();
// At what index to add?
int whereInsert = get_Index_Insert(arrayInput, lenghtArray, insertValue);
// Add it now:
for (int i = 0; i < whereInsert; i++)
arrayOutput.push_back(arrayInput[i]);
arrayOutput.push_back(insertValue);
for (int i = whereInsert + 1; i < lenghtArray + 1; i++)
arrayOutput.push_back(arrayInput[i - 1]);
return arrayOutput;
}
vector<int> insert_Value2(const vector<int>& arrayInput, int insertValue)
{
vector<int> arrayOutput;
int lenghtArray = arrayInput.size();
// At what index to add?
int whereInsert = get_Index_Insert2(arrayInput, lenghtArray, insertValue);
// Add it now:
for (int i = 0; i < whereInsert; i++)
arrayOutput.push_back(arrayInput[i]);
arrayOutput.push_back(insertValue);
for (int i = whereInsert + 1; i < lenghtArray + 1; i++)
arrayOutput.push_back(arrayInput[i - 1]);
return arrayOutput;
}
int main()
{
{
// START TIME
auto start = high_resolution_clock::now();
vector<int> array{ 26, 21, 13, 11, 8, 3, 2 };
array = insert_Value(array, 22);
array = insert_Value(array, 17);
array = insert_Value(array, 1);
array = insert_Value(array, 43);
auto stop = high_resolution_clock::now();
// END TIME
// Show time:
auto duration = duration_cast<microseconds>(stop - start);
cout << "Time taken by function 1, linear search: " << duration.count() << " microseconds" << endl;
for (int i = 0; i < array.size(); i++)
cout << array[i] << " ";
cout << endl;
}
{
// START TIME
auto start = high_resolution_clock::now();
vector<int> array{ 26, 21, 13, 11, 8, 3, 2 };
array = insert_Value2(array, 22);
array = insert_Value2(array, 17);
array = insert_Value2(array, 1);
array = insert_Value2(array, 43);
auto stop = high_resolution_clock::now();
// END TIME
// Show time:
auto duration = duration_cast<microseconds>(stop - start);
cout << "Time taken by function 2, binary search: " << duration.count() << " microseconds" << endl;
for (int i = 0; i < array.size(); i++)
cout << array[i] << " ";
cout << endl;
}
cout << endl << endl << endl;
return 0;
}
Other info that may help in deciding recommended method:
I cannot use anything else than class vector from STL; (only using it as a holder + it's push_back function, nothing else as helper function from it);
I will not have more than a 1000 elements ever in the vector.
Is there any way better to do it than above? in less complexity involved? Any source material I may have missed and that might help is very much appreciated also.
EDIT:
After some more investigations and using binary search method while seeking index position for actual element insertion (thanks to the debates from comments), edited my above sample a bit, testing execution time of a "get_Index_Insert2(...) function using early returns and binary search.
Times received (microseconds), after 3 runs:
Time taken by function 1, linear search: 60 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 2, binary search: 33 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 1, linear search: 61 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 2, binary search: 34 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 1, linear search: 61 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 2, binary search: 34 microseconds
43 26 22 21 17 13 11 8 3 2 1
Instead of creating a new vector you can use the insert function to put the new value into the existing list at the desired index. See https://en.cppreference.com/w/cpp/container/vector/insert
void insert_Value(const vector<int>& arrayInput, int insertValue)
{
int lenghtArray = arrayInput.size();
// At what index to add?
int whereInsert = get_Index_Insert(arrayInput, lenghtArray, insertValue);
arrayInput.insert(whereInsert, insertValue);
}
#include <algorithm>
#include<iostream>
#include<vector>
using namespace std;
std::vector<int>::const_iterator get_Index_Insert(const vector<int>& array ,int insertValue) {
return std::find_if(array.cbegin(),array.cend(),[insertValue](int aValue) { return aValue < insertValue;});
}
void insert_Value(vector<int>& arrayInput, int insertValue, std::vector<int>::const_iterator aIt)
{
arrayInput.insert(aIt,insertValue);
}
int main()
{
vector<int> array{26, 21, 13, 11, 8, 3, 2 };
auto myIt = get_Index_Insert(array,22);
insert_Value(array,22,myIt);
for (int i = 0; i < array.size(); i++)
cout << array[i] << " ";
cout << endl << endl << endl;
return 0;
}
This is only an idea, then it can be enhanced
You don't need to pass the size of the vector, std::vector already have a member function size().
I think you overcomplicated things. You just have to iterate over the vector and compare each element with the value you want to insert. If the comparison evaluates to false, then you found where to insert the new element.
You may implement the function the following way:
template <typename val_t, typename Compare>
void insert_ordered(std::vector<val_t> & vec, const val_t & val, Compare comp)
{
bool inserted(false);
for(typename std::vector<val_t>::iterator it = vec.begin(); !inserted && (it != vec.end()); ++it)
{
if(!comp(*it, val))
{
vec.insert(it, val);
inserted = true;
}
}
if(!inserted)
vec.push_back(val);
}
It takes the vector, the value to instert and the comparison function you want.
For your use case, it may be used like this:
int main()
{
std::vector<int> v {26, 21, 13, 11, 8, 3, 2};
insert_ordered(v, 22, std::greater<int>());
insert_ordered(v, 17, std::greater<int>());
insert_ordered(v, 1, std::greater<int>());
insert_ordered(v, 43, std::greater<int>());
for(const int & i : v)
std::cout << i << ' ';
return 0;
}
Output:
43 26 22 21 17 13 11 8 3 2 1
Live example
If, for some reason, you can't use std::greater, you can define your own comparator like this:
auto desc_comp = [](const int & lhs, const int & rhs)
{
return lhs > rhs;
};
And use it like this:
insert_ordered(v, 22, desc_comp);
Edit:
If you don't mind having several exit points in the function, it can be simplified as:
template <typename val_t, typename Compare>
void insert_ordered(std::vector<val_t> & vec, const val_t & val, Compare comp)
{
for(typename std::vector<val_t>::iterator it = vec.begin(); it != vec.end(); ++it)
{
if(!comp(*it, val))
{
vec.insert(it, val);
return;
}
}
vec.push_back(val);
}

In C++, how can I write a function that flips a 2d array at a specified position?

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

Erasing an element from 2D vector c++

I have a unsymmetrical vector in 2D.
vector< vector<int> > Test
where Test =
2 4 6 5 7
6 5 7 9 10
5 9 10
9 10
I am reading the row 1 and if any element of this is present in other rows then delete it.
for eaxmple.. After reading row 1, i have to remove 6, 5, and 7 from other rows.
However, It is not working
Here is the code i am trying
Test[i].erase(Test[i].begin()+j);
where i = row and j is col.
My code is :
for (i =0; i < Test.size();i++)
{
for (j=0; j < Test[i].size();j++)
{
// removed repeated element
if (i >0)
{
Test[i].erase(Test[i].begin() +j);
}
}
}
Maybe it is nor very nice but it works
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<std::vector<int>> v =
{
{ 2, 4, 6, 5, 7 },
{ 6, 5, 7, 9, 10 },
{ 5, 9, 10 },
{ 9, 10 }
};
for ( const auto &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
if ( !v.empty() )
{
for ( auto it = std::next( v.begin() ); it != v.end(); ++it )
{
auto is_present = [&]( int x )
{
return std::find_if( v.begin(), it,
[x]( const std::vector<int> &v1 )
{
return std::find( v1.begin(), v1.end(), x ) != v1.end();
} ) != it;
};
it->erase( std::remove_if( it->begin(), it->end(), is_present ),
it->end() );
}
}
for ( const auto &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
2 4 6 5 7
6 5 7 9 10
5 9 10
9 10
2 4 6 5 7
9 10
You can place the values encountered in each row in a set, and then query every element in a new row for existence in that set. Such a function would look like this :
void RemoveRowDuplicates(vector<vector<int>> &v)
{
std::set<int> vals;
for(auto &vec : v)
{
vec.erase(remove_if(vec.begin(), vec.end(), [&](int k){
return vals.find(k) != vals.end();
}), vec.end());
vals.insert(vec.begin(), vec.end());
}
}
What exactly do you think is Test[i].begin()+j? Is ist a set of elements you want to erase? I don't think so. It should be just an iterator, that points to a single element, but you want to delete all elements, that are already in your datastructure.
If I understood, what you want to do, try:
for(int j = 0; j < Test.size(); j++){ //iterate over other rows
if(j == i)
continue;
for(int k = 0; k < Test[j].size(); k++){ //iterate over elements of the rows
int elementToRemove = (Test[j])[k];
vector<int>::iterator it = Test[i].begin();
while (it != Test[i].end()) { //iterate over row i
if((*it) == elementToRemove){ //erase the element if it matches the actual
it = Test[i].erase(it);
}else{
it++;
}
}
}
}
You could execute the code for every possible i. Maybe start form i = 0 to n. If I refer to your code, that you added put the code above in between your
for (i =0; i < Test.size();i++){
//my code here...
}
Edit: Used iterator now to delete. The first version was not correct.
Edit2: Changed the index of the first loop and added continue statement.
This works for me:
int i = 0;
for ( int j = i+1; j < Test.size(); ++j )
{
for ( int k = 0; k < Test[i].size(); ++k )
{
std::vector<int>::iterator iter = Test[j].begin();
std::vector<int>::iterator end = Test[j].end();
for ( ; iter != end; )
{
if ( *iter == Test[i][k] )
{
iter = Test[j].erase(iter);
}
else
{
++iter;
}
}
}
}
Consider the following 2D vector
myVector=
1 2 3 4 5 -6
6 7 8 -9
8 -1 -2 1 0
Suppose we want to delete the element myVector[row][column] for appropriate row and column indices.
Look at the following code:
void delete_element(vector<int>& temp, col)
{
temp.erase(temp.begin()+col);
}
int main()
{
//Assume that the vector 'myVector' is already present.
cin>>row>>column;
delete_element(myVector[row],column);
}
What we basically do is,we get the row and column of the element to be deleted. Now as this 2D vector is a vector of vectors, we pass the vector(the row containing the element to be deleted) and the column as parameters to a function. Note that the row-vector is passed as a reference ('&' in vector parameter).
Now the problem becomes quite as simple as deleting an element from a 1D vector.
Hope this helps!

Numbering elements in vector

I have a vector of integers. For example: 26 58 32 47 . I need to replace them with their number in that sequence. In this case it would be: 4 1 3 2 . I tried this code:
int n = 1;
vector <int> vietos;
for (vector <int>::iterator i = vieta.begin(); i != vieta.end(); i++) {
for (vector <int>::iterator j = vieta.begin(); j != vieta.end(); j++) {
if (*i > *j)
n++;
}
vietos.push_back(n);
cout << n << " ";
n = 1;
}
Having numbers 23 25 38 28 26 28 (Note: In this case I number them in reverse order!) I get: 1 2 6 4 3 4 which is good except for two numbers are equal.
Maybe there is some way to number elements in vector using STL algorithms?
In my opinion the simplest way is to use std::reference_wrapper. The code will look simple and very clear.
Here is the program that demonstrates the approach.
Enjoy!:)
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main()
{
std::vector<int> v = { 23, 25, 38, 28, 26, 28 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
// Introducing a local block scope that the auxiliary vector would be automatically deleted
{
std::vector<std::reference_wrapper<int>> vr( v.begin(), v.end() );
std::stable_sort( vr.begin(), vr.end() );
for ( std::vector<std::reference_wrapper<int>>::size_type i = 0;
i < vr.size();
i++ )
{
vr[i].get() = i + 1;
}
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
23 25 38 28 26 28
1 2 6 4 3 5
If you need to get the reverese order all you need is to add to the code functional object
std::greater<std::reference_wrapper<int>>()
in the call of std::stable_sort
For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main()
{
std::vector<int> v = { 23, 25, 38, 28, 26, 28 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
// Introducing a local block scope that the auxiliary vector would be automatically deleted
{
std::vector<std::reference_wrapper<int>> vr( v.begin(), v.end() );
std::stable_sort( vr.begin(), vr.end(),
std::greater<std::reference_wrapper<int>>() );
for ( std::vector<std::reference_wrapper<int>>::size_type i = 0;
i < vr.size();
i++ )
{
vr[i].get() = i + 1;
}
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
23 25 38 28 26 28
6 5 1 2 4 3
Is not it the best solution is it? :)
EDIT: Maybe there is no sense to use std::stable_sort with the functional object. It will be enough to use for loop setting numbers in the reverse order. Something as
for ( std::vector<std::reference_wrapper<int>>::size_type i = 0;
i < vr.size();
i++ )
{
vr[vr.size() + i - 1].get() = i + 1;
}
In that case, you should increment when the value is greater than or equal to rather than just greater than, try this:
(*i >= *j)
If you were to replace the iterators with integers, i.e.: (I assume < isn't defined on iterators, but it could be)
for (int i = 0; i < vietos.size(); i++)
You could increment n as well when elements to the left are equal, i.e. when
vietos[i] > vietos[j] || (vietos[i] == vietos[j] && j < i).
Alternatively, you could create a vector<pair<int, int> >, with each pair containing the element and its index, then sort that, and iterate through the sorted vector, setting the index in the pair in the original vector to the index in the sorted vector.
This would give an O(n log n) running time, as opposed to the O(n²) of the above.
Pseudo-code:
vector arr
vector<pair> pairs
for i = 0 to n
pairs.insert(arr[i], i)
sort pairs
for i = 0 to n
arr[pairs[i].second] = i

How to make double sort integer arrays using C++?

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!