sorting a 2d array by one row - c++

I have a really specified problem to deal with. I need to descending sort an array[4][x].
From instance if i get values like:
{121,120,203,240}
{0.5,0.2,3.2,1.4}
{1.3,1.5,1.2,1.8}
{3 ,2 ,5 ,4 }
All values have to bo sorted by the 4th row. Thus, I need an output like this:
{203,240,121,120}
{3.2,1.4,0.5,0.2}
{1.2,1.8,1.3,1.5}
{5 ,4 ,3 ,2 }
I have tried doing it by the bubble sort method, but it does not work properly.

A straightforward approach of sorting the array using the bubble sort can look the following way
#include <iostream>
#include <iomanip>
#include <utility>
int main()
{
const size_t N = 4;
double a[][N] =
{
{ 121, 120, 203, 240 },
{ 0.5, 0.2, 3.2, 1.4 },
{ 1.3, 1.5, 1.2, 1.8 },
{ 3, 2, 5, 4 }
};
for (const auto &row : a)
{
for (double x : row) std::cout << std::setw( 3 ) << x << ' ';
std::cout << '\n';
}
std::cout << std::endl;
// The bubble sort
for (size_t n = N, last = N; not (n < 2); n = last)
{
for (size_t i = last = 1; i < n; i++)
{
if (a[N - 1][i - 1] < a[N - 1][i])
{
for (size_t j = 0; j < N; j++)
{
std::swap(a[j][i - 1], a[j][i]);
}
last = i;
}
}
}
for (const auto &row : a)
{
for (double x : row) std::cout << std::setw( 3 ) << x << ' ';
std::cout << '\n';
}
std::cout << std::endl;
return 0;
}
The program output is
121 120 203 240
0.5 0.2 3.2 1.4
1.3 1.5 1.2 1.8
3 2 5 4
203 240 121 120
3.2 1.4 0.5 0.2
1.2 1.8 1.3 1.5
5 4 3 2
All you need is to extract the code of the bubble sort from main and rewrite it as a separate function for any 2D array and any row used as the criteria of sorting.

The problem would be easy to solve if instead of parallel vectors we had a structure containing parallel values.
It is easy enough to get back to such a structure: just create some intermediate vector containing sort keys and indexes and sort it.
After sorting the indexes are giving us a direct way to reorder all the individual vectors in the right order.
I would do something like below (I put it in a Boost Unit Test, but what is done should be obvious) .
#define BOOST_AUTO_TEST_MAIN
#define BOOST_TEST_MODULE TestPenta
#include <boost/test/auto_unit_test.hpp>
#include <iostream>
#include <vector>
std::vector<int> v1 = {121,120,203,240};
std::vector<float> v2 = {0.5,0.2,3.2,1.4};
std::vector<float> v3 = {1.3,1.5,1.2,1.8};
std::vector<int> v4 = {3 ,2 ,5 ,4 };
std::vector<int> expected_v1 = {203,240,121,120};
std::vector<float> expected_v2 = {3.2,1.4,0.5,0.2};
std::vector<float> expected_v3 = {1.2,1.8,1.3,1.5};
std::vector<int> expected_v4 = {5 ,4 ,3 ,2 };
BOOST_AUTO_TEST_CASE(TestFailing)
{
// First create an index to sort containing sort key and initial position
std::vector<std::pair<int,int>> vindex{};
int i = 0;
for (auto x: v4){
vindex.push_back(std::pair<int,int>(x,i));
++i;
}
// Sort the index vector by key value
struct CmpIndex {
bool operator() (std::pair<int, int> & a, std::pair<int, int> & b) {
return a.first > b.first ;
}
} cmp;
std::sort(vindex.begin(), vindex.end(), cmp);
// Now reorder all the parallel vectors using index
// (of course in actual code we would write some loop if several vector are of the same type).
// I'm using parallel loops to avoid using too much memory for intermediate vectors
{
std::vector<int> r1;
for (auto & p: vindex){
r1.push_back(v1[p.second]);
}
v1 = r1;
}
{
std::vector<float> r2;
for (auto & p: vindex){
r2.push_back(v2[p.second]);
}
v2 = r2;
}
{
std::vector<float> r3;
for (auto & p: vindex){
r3.push_back(v3[p.second]);
}
v3 = r3;
}
{
std::vector<int> r4;
for (auto & p: vindex){
r4.push_back(v4[p.second]);
}
v4 = r4;
}
// Et voila! The vectors are all sorted as expected
i = 0;
for (int i = 0 ; i < 4 ; ++i){
BOOST_CHECK_EQUAL(expected_v1[i], v1[i]);
BOOST_CHECK_EQUAL(expected_v2[i], v2[i]);
BOOST_CHECK_EQUAL(expected_v3[i], v3[i]);
BOOST_CHECK_EQUAL(expected_v4[i], v4[i]);
++i;
}
}

Related

C++ EIGEN: How to create triangular matrix map from a vector?

I would like to use data stored into an Eigen (https://eigen.tuxfamily.org) vector
Eigen::Vector<double, 6> vec({1,2,3,4,5,6});
as if they were a triangular matrix
1 2 3
0 4 5
0 0 6
I know how to do it for a full matrix using Eigen's Map
Eigen::Vector<double, 9> vec({1,2,3,4,5,6,7,8,9});
std::cout << Eigen::Map<Eigen::Matrix<double, 3, 3, RowMajor>>(vec.data());
which produces
1 2 3
4 5 6
7 8 9
However I do not know how to make a Map to a triangular matrix.
Is it possible?
Thanks!
[Edited for clarity]
In my opinion this cannot be done using Map only: The implementation of Map as it is relies on stride sizes that remain constant no matter their index positions, see https://eigen.tuxfamily.org/dox/classEigen_1_1Stride.html.
To implement a triangular matrix map you would have to have a Map that changes its inner stride depending on the actual column number. The interfaces in Eigen do not allow that at the moment, see https://eigen.tuxfamily.org/dox/Map_8h_source.html.
But if you are just concerned about the extra memory you can just use Eigen's sparse matrix representation:
https://eigen.tuxfamily.org/dox/group__TutorialSparse.html
(Refer to section "Filling a sparse matrix".)
This is not a direct solution to your problem but a way how to calculate the std::vector to fill in the 0 at the correct place. I think it is also possible to calculate it as a std::array if needed. I am not sure if that helps, but I guess you could use the calculated vector to fill the Eigen::Map
#include <array>
#include <cstddef>
#include <iostream>
#include <vector>
template<typename T, size_t N>
class EigenVector
{
static constexpr int CalculateRowColSize(size_t n)
{
size_t i = 1;
size_t inc = 1;
do
{
if (inc == n)
{
return static_cast<int>(i);
}
i++;
inc += i;
} while (i < n);
return -1;
}
static constexpr bool IsValid(size_t n)
{
if(CalculateRowColSize(n) == -1)
{
return false;
}
return true;
}
static_assert(IsValid(N));
public:
EigenVector() = delete;
static std::vector<T> Calculate(std::array<T, N> values)
{
constexpr size_t mRowColSize = CalculateRowColSize(N);
std::vector<T> ret;
auto count = 0;
auto valueCounter = 0;
for (size_t i = 0; i < mRowColSize; i++)
{
for (auto j = 0; j < count; j++)
{
ret.push_back(T());
}
for (size_t j = 0; j < mRowColSize - count; j++)
{
ret.push_back(values[valueCounter]);
valueCounter++;
}
count++;
}
return ret;
}
};
int main()
{
{
const std::array<int, 6> arr{ 1,2,3,4,5,6 };
const auto values = EigenVector<int, 6>::Calculate(arr);
for (auto& val : values)
{
std::cout << val << " ";
}
}
std::cout << std::endl << std::endl;
{
const std::array<int, 10> arr{ 1,2,3,4,5,6,7,8,9,10 };
const auto values = EigenVector<int, 10>::Calculate(arr);
for (auto& val : values)
{
std::cout << val << " ";
}
}
return 0;
}
Output:
1 2 3 0 4 5 0 0 6
1 2 3 4 0 5 6 7 0 0 8 9 0 0 0 10
Note that the algorithm is written that only possible matrix sizes are valid as input

How to find indexes from vector1 in vector2 in c++

i was envolving about a week with this issue, i have two vector for example vec1 and vec2, i want after search and find values from vec1 in vec2 return their indexes where only found for example:
vector<int>vec2 = { 1, 2, 2, 4 };
vector<int>vec1 = { 1, 2, 4 };
i want somthing like this pseudo code and this result:
pseudo code:
for i = 0 to vec2.size() do
return vec1 indexes in vec2;
end
result:
pass1:
1 0 0 0
pass2:
0 1 1 0
pass3:
0 0 0 1
final resault:
0 0 0 1
My code (it does not compile):
My code:
#include <vector>
#include <iostream>
using namespace std;
vector<int> find_index(vector<int>vec2, vector<int>vec1)
{
std::vector<double> tmp;
for (int i = 0; i<vec2.size(); i++)
{
for (int j = 0; j<vec2.size(); j++)
{
if (vec2[i] == vec1[j])
{
tmp.push_back(i);
}
}
}
return tmp;
}
int main()
{
vector<int>vec2 = { 1, 2, 2, 4 };
vector<int>vec1 = { 1, 2, 4 };
cout << find_index(vec2, vec1);
getchar();
return 0;
}
The code you have fails to compile for two reasons:
Using double item type for the tmp vector. A vector<double> does not convert implicitly to the required function result type vector<int>.
The standard library does not define output of vectors, so the cout << a vector in main doesn't compile.
To output the vector you can define function like this:
void write_to( ostream& stream, vector<int> const& v )
{
for( int i = 0; i < int( v.size() ); ++i )
{
stream << (i > 0? " " : "") << v[i];
}
}
and call it like this:
write_to( cout, find_index(vec2, vec1) );
cout << "\n";
It's also possible to write a little glue code that would enable the cout << notation, i.e. that would make it use the write_to function, but that is maybe just complication now.
With these changes your code compiles and outputs
0 1 2 3

Conditional Averaging of a vector based on similarities in another vector c++

It is best to give an example.
Let's say vector A consists of:
A = {3 ,2 ,1 ,4 ,6 ,3 ,8 ,4}
and vector B consists of:
B = {1.5,2 ,2 ,1.5,3 ,3 ,3 ,2}
The unique values in vector B are {1.5, 2, 3}
I want the resulting vector RESULT to be:
RESULT[0] = Average(A given B=1.5) = Average(3,4)
RESULT[1] = Average(A given B=2 ) = Average(2,1,4)
RESULT[2] = Average(A given B=3 ) = Average(6,3,8)
What is the most efficient way of calculating this. My own method is to loop over unique elements of B, and for each of them, loop over each B value trying to match that unique number and keep summing up the corresponding element of vector A in each match, also counting the number of matches so I can find the average.
This is too slow. since My vector A is 8M elements, and vector B consists of 0.5M unique values.
Any help would be appreciated.
Here's a lazy idea: Traverse both vectors in lockstep and aggregate the results in a separate container. For example:
#include <cassert>
#include <cmath>
#include <iostream>
#include <map>
#include <utility>
std::map<double, std::pair<int, std::size_t>> m;
assert(A.size() == B.size());
for (std::size_t i = 0; i != A.size(); ++i)
{
assert(!std::isnan(B[i]));
auto & p = m[B[i]];
p.first += A[i];
p.second += 1;
}
In the end you just report the results:
for (const auto & p : m)
std::cout << "Average for bin " << p.first << " is "
<< static_cast<double>(p.second.first) / p.second.second
<< "\n";
(Beware that your key value must not be NaN: in an ordered map, NaN is not part of the strict ordering; in an unordered map, it does not compare equal to itself.)
You can do a loop with a (hash) table: see it Live On Coliru
int main()
{
vector<int> A = {3 ,2 ,1 ,4 ,6 ,3 ,8 ,4};
vector<double> B = {1.5,2 ,2 ,1.5,3 ,3 ,3 ,2};
assert(A.size() == B.size());
struct accum {
uintmax_t sum = 0;
size_t number_of_samples = 0;
void sample(int val) { sum += val; ++number_of_samples; }
};
map<double, accum> average_state;
for(size_t i = 0; i<B.size(); ++i)
average_state[B[i]].sample(A[i]);
for(auto& entry : average_state)
{
accum& state = entry.second;
double average = static_cast<double>(state.sum) / state.number_of_samples;
std::cout << "Bucket " << entry.first << "\taverage of " << state.number_of_samples << " samples:\t" << average << "\n";
}
}
Prints
Bucket 1.5 average of 2 samples: 3.5
Bucket 2 average of 3 samples: 2.33333
Bucket 3 average of 3 samples: 5.66667

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!

Slicing a vector

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