views:

73

answers:

3

Hi guys,

I've got a bidimensional array of objects (a 2D vector containing GridCell instances) as in here:

typedef vector<GridCell> CellArray;
typedef vector<CellArray> TwoDCellArray;
TwoDCellArray CellArr2D;

I am currently drawing all the cells like this:

for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
        CellArr2D[i][j].draw()
    }
}

However, I've got a depth problem and I should draw the instances depending on its size (size property, CellArr2D[i][j].size).

What should I do to sort this array without changing it's i,j values? Copying all the objects to a secondary array and sort that one? And more imporntant, hence this post... how can I sort an Array (Vector) by it's contained object property?

Thanks in advanced.

+3  A: 

Create a vector of pairs (i,j) and sort it by size property.

typedef std::pair<int, int> int_pair_t;
typedef std::vector< int_pair_t > size_index_t;

namespace {
struct sort_helper {
    sort_helper( const TwoDCellArray& arr ) : arr_(arr) {}      
    bool operator()( const int_pair_t& ind1, const int_pair_t& ind2 ) { 
      return arr_[ind1.first][ind1.second].size > arr_[ind2.first][ind2.second].size; 
    }
private:
    const TwoDCellArray& arr_;
};

struct draw_helper {
    draw_helper( TwoDCellArray& arr ) : arr_(arr) {}        
    void operator()( const int_pair_t& ind ) { 
        arr_[ind.first][ind.second].draw();
    }
private:
    TwoDCellArray& arr_;
};
}

void some_func()
{
    // initialize helper array of indices
    size_index_t index;
    index.reserve( rows*cols );
    for ( int i = 0; i < rows*cols; ++i )
        index.push_back( make_pair( i/cols%rows, i%cols ) );

    // sort according to the `size` field
    std::sort( index.begin(), index.end(), sort_helper( CellArr2D ) );

    // draw
    std::for_each( index.begin(), index.end(), draw_helper( CellArr2D ) );
}
Kirill V. Lyadvinsky
I get this in Xcodeerror: no matching function for call to 'sort(__gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >, __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >, Grid::update()::sort_helper)'I tried adding #include <algorithm> but didn't work.
ozke
`sort_helper` and `draw_helper` are shouldn't be local classes in C++'03 (it is allowed only in C++0x). Move them out of your function.
Kirill V. Lyadvinsky
So fixed the code to make it clear.
Kirill V. Lyadvinsky
Err... I get an EXC_BAD_ACCESS in here:return arr_[ind1.first][ind2.second].size > arr_[ind2.first][ind2.second].size;
ozke
there was a typo in the code
Kirill V. Lyadvinsky
Thanks! Still same error though... :S
ozke
The cause of that error is that your `CellArr2D` doesn't contain some elements. Are you sure you have filled it with `rows*cols` elements? If no then you need to add appropriate checks in the `sort_helper`.
Kirill V. Lyadvinsky
I'll double-check. Thank you :)
ozke
Ok. I got it working after changing the pair values.I used a nested for loop (rows and cols).To do it your way... Why are you using "i % cols, i / rows"? Shouldn't it be "i/cols, i % cols"? (let's say there are 6 cols... that would give us 0-0, 0-1, 0-2...)
ozke
Did you tried it?
ozke
Well, I'm getting X and Y position from a cell number. If it's cell number 6 (7th cell as it's 0-based) and there's 5 columns then X=1 and Y=1. That's why I think it's i/cols, i % cols. ANYWAY, thanks a lot for your help. You're suggested solution works great after the tweaks. :)
ozke
I've tested it. There was a bug in that loop, now I fixed it.
Kirill V. Lyadvinsky
+1  A: 

Use std::sort and supply a custom comparison function object to sort by a user-defined property or other relation.

As for how it should be sorted, if you want to sort it but not change it, then you will have to copy the array. The best way to do this is store your GridCells on the heap and store smart pointers to them in the vectors. This way, sorting and copying them will involve less overhead.

DeadMG
A: 

You can put references in a secondary array and sort that one:

struct CellRef
{
  CellRef(GridCell& cell) : m_c(cell) {}
  bool operator<(const CellRef& r) const { return m_c.size < r.m_c.size; }
  GridCell& data() { return m_c; }
private:
  GridCell& m_c;
};

vector<CellRef> refs;
for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
        refs.push_back(CellArr2D[i][j]);
    }
}
std::sort(refs.begin(), refs.end());
for(vector<CellRef>::iterator it=refs.begin(), end=refs.end(); it!=end; ++it)
  it->data().draw();
jpalecek