the_toast
the_toast

Reputation: 185

STL Compliant iterator for two arrays

I want to sort two arrays a and b of the same size in the following way: Array b is ordered the same way array a is being sorted. Example input:

a = {3, 1, 5}
b = {2, 6, 4}

Example out

a = {1, 3, 5}
b = {6, 2, 4}

Such that the values of b are irrelevant for their reordering, but instead follow the reordering of array a.

I want to use stl::sort to do this, and i need to do it as efficiently as possible. So I don't want to copy all elements into structs or order an array with the index which i afterwards could use to order the arrays a and b. What i thought would be the least overhead should be a RandomAccessIterator (since sort requires random access). Now my problem is, I'm really not that good in C++. If someone could give me hints on a level a noob could understand i'd be delighted. I've found some solutions:

Sorting two corresponding arrays, but both proposed solutions don't seem performant enough,

http://www.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html which uses boost stuff which I assume breaks the compliance with stl (also honestly I don't understand all the template stuff used there, i have a double and an int array and the size n of both, so i don't think i need templates), and finally this

http://www.c-plusplus.de/forum/313698-full solution where i got stuck at the point that i don't know how to implement operator-> and operator* since i don't know if i can return only one value (the value from array a), i.e. if this value is used only for comparison or also for assigning values. also the solution in this thread compares the pointer values for the comparison operators, which i'm not sure is correct (shouldn't it be the values behind the pointers?).

Here's what i have so far, if you see horrible noob mistakes pls tell me where i went wrong :)

#include "DoubleArrayRAccIterator.h"


DoubleArrayRAccIterator::~DoubleArrayRAccIterator() {
    // TODO Auto-generated destructor stub
}
struct doubleValue{
    double* a_val;
    int* b_val;
};

double::DoubleArrayRAccIterator::DoubleArrayRAccIterator(double& a_arr,int& b_arr, int size) {
    a_begin = &a_arr;
    b_begin = &b_arr;
    a = &a_arr;
    b = & b_arr;
    n = size;
}

DoubleArrayRAccIterator::DoubleArrayRAccIterator() {
    a = 0;
    b = 0;
    n = 0;
}

DoubleArrayRAccIterator::DoubleArrayRAccIterator(const DoubleArrayRAccIterator& it) {
    a = it.a;
    b = it.b;
    n = it.n;
}

DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator=(const DoubleArrayRAccIterator& it) {
    a = it.a;
    b = it.b;
    n = it.n;
    return *this;
}

DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator++() {
    ++a;
    ++b;
    return *this;
}


DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator--() {
    --a;
    --b;
    return *this;
}

DoubleArrayRAccIterator DoubleArrayRAccIterator::operator++(int) {
    DoubleArrayRAccIterator it(*this);
    ++a;
    ++b;
    return it;
}


DoubleArrayRAccIterator DoubleArrayRAccIterator::operator--(int) {
    --a;
    --b;
    return *this;
}

DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator+=(diff_type x) {
    a += x;
    b += x;
    return *this;
}


DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator-=(diff_type x) {
    a += x;
    b += x;
    return *this;
}

DoubleArrayRAccIterator DoubleArrayRAccIterator::operator+(diff_type x) const {
    a += x;
    b += x;
    return *this;
}


typename DoubleArrayRAccIterator DoubleArrayRAccIterator::operator-(diff_type x) const {
    a -= x;
    b -= x;
    return *this;
}


DoubleArrayRAccIterator DoubleArrayRAccIterator::operator+(const DoubleArrayRAccIterator& it) const {
    a += it.a;
    b += it.b;
    return *this;
}


DoubleArrayRAccIterator DoubleArrayRAccIterator::operator-(const DoubleArrayRAccIterator& it) const {
    a -= it.a;
    b -= it.b;
    return *this;
}


DoubleArrayRAccIterator::reference DoubleArrayRAccIterator::operator*() const {
    // this MUST be wrong, only return value of array a?
    doubleValue result;
    result.a_val=a;
    result.b_val=b;
    return *result;
}

DoubleArrayRAccIterator::pointer DoubleArrayRAccIterator::operator->() const {
    // this MUST be wrong, only return value of array a?
    doubleValue result;
    result.a_val=a;
    result.b_val=b;
    return &result;
}


DoubleArrayRAccIterator::reference DoubleArrayRAccIterator::operator[](diff_type x) const {
    // this MUST be wrong, only return value of array a?
    doubleValue result;
    result.a_val=a_begin+x;
    result.b_val=b_begin+x;
    return *result;
}


bool DoubleArrayRAccIterator::operator==(const DoubleArrayRAccIterator& it) const {
    return a == it.a;
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator!=(const DoubleArrayRAccIterator& it) const {
    return a != it.a;
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator<(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator>(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator<=(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator>=(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


DoubleArrayRAccIterator begin() {
    return DoubleArrayRAccIterator(a_begin, b_begin, n);
}


DoubleArrayRAccIterator end() {
    return DoubleArrayRAccIterator(a_begin + n, b_begin + n, n);
}

And if anyone didn't stop reading yet and still has patience, i'm confused by the "diff_type", "reference" and "pointer" types i just copied from here http://www.c-plusplus.de/forum/313698-full, what are they supposed to be?

Upvotes: 2

Views: 661

Answers (2)

JBentley
JBentley

Reputation: 6260

I'm a little confused by your question, but since you linked to this question, I assume you're trying to solve the same problem as that i.e. you want to sort array a and you want the indices of array b rearranged in the same way they were for a.

This sounds to me like it could be an XY Problem. If at all possible, redesign your code so that you do not have parallel arrays. Instead, place each element of a with its corresponding element of b in a class or std::pair, put those in a collection such as an array or vector, and sort that (possibly overloading the comparison operators, if required).

Upvotes: 0

PiotrNycz
PiotrNycz

Reputation: 24420

If I understand you correctly you have this case:

[a1][a2][a3]....[an]
[b1][b2][b3]....[bn]

You want to sort by array a, both of these arrays in the same way, so the result is:

[ax1][ax2][ax3]....[axn]
[bx1][bx2][bx3]....[bxn]

Where xi are indeces same for both arrays.

Consider this example:

class SIter {
public:


   SIter(int* aIter, double* bIter) : aIter(aIter), bIter(bIter) {}

  // we move to next position is just moving both:
  SIter& operator ++() {
     ++aIter; ++bIter;
     return *this;
  }
  SIter operator ++(int) {
     SIter rv = *this;
     ++aIter; ++bIter;
     return rv;
  }
  SIter& operator --() {
     --aIter; --bIter;
     return *this;
  }
  SIter operator --(int) {
     SIter rv = *this;
     --aIter; --bIter;
     return rv;
  }
  SIter operator + (std::ptrdiff_t cc) const
  {
      SIter rv = *this;
      rv.aIter += cc;
      rv.bIter += cc;
      return rv;
  }
  SIter operator - (std::ptrdiff_t cc) const
  {
      SIter rv = *this;
      rv.aIter -= cc;
      rv.bIter -= cc;
      return rv;
  }
  std::ptrdiff_t operator - (SIter other) const
  {
      return aIter - other.aIter;
  }
   struct value_type {
      int a; double b;
      bool operator < (const value_type& other) const {
          return a < other.a; // this is the place where way of sorting is defined!!!!
      }
   };
  struct reference {
     int* a;
     double* b;
     reference& operator = (const value_type& o) 
     {
       *a = o.a;
       *b = o.b;
       return *this;
     }
     operator value_type() const {
         value_type rv = { *a, *b };
         return rv;
     }
     reference& operator = (const reference& other)
     {
        *a = *other.a;
        *b = *other.b;
        return *this;
     }
     bool operator < (const reference& other) const {
        return *a < *other.a; 
     }
     bool operator < (const value_type& other) const {
        return *a < other.a; 
     }
  };

  reference operator * () {
     reference rv = { aIter, bIter };
     return rv;
  }
  bool operator == (const SIter& other) const
  {
      return aIter == other.aIter; // don't need to compare bIter - shall be in sync
  }
  bool operator != (const SIter& other) const
  {
      return aIter != other.aIter; // don't need to compare bIter - shall be in sync
  }
  bool operator < (const SIter& other) const
  {
      return aIter < other.aIter; // don't need to compare bIter - shall be in sync
  }
  // I bet you don't need pointer operator -> ()
   typedef std::random_access_iterator_tag iterator_category;
   typedef std::ptrdiff_t difference_type;
   typedef reference pointer;


private:
  int* aIter; 
  double* bIter;
};

Then use like this:

int main() {
   int a[100] = {};
   double b[100] = {};

   SIter beginIter(a, b);
   SIter endIter(a + 100, b + 100);

   std::sort(beginIter, endIter);

}

I did not try this and probably it has some drawbacks, but you should go in this direction. Your iterator shall consists of two pointers to your arrays (in more general way - iterators to your containers) and your reference type shall shall have operator = and operator < which will be able to assign elements of your both arrays and compare only elements of one array.

[UPDATE]

Good news: I did the working example: ideone

Upvotes: 4

Related Questions