I was once trained in C and C++ and am now brushing off the
cobwebs and relearning C++. I am restudying the Borland C++
Builder and realized I needed to know more C++, so I began
restudying Visual C++...by Spencer and Perry.

I am writing software to anazlyze lake water quality data I gather.
So far I am doing OK, moving slowly (within C++ console apps
only) because this project is fairly difficult, but now I
have hit a wall: sorting data. In brief, here is what I am
trying to do:

1. Open filestream to data file. My code writes binary
objects to the hard drive with streamname.write and reads
them back with streamname.read. Each object is a C++ class.
This is now working OK.
2. As I read each object from the file, I store all its
members in an array and confirm that each object was
successfully stored in the array. I have confirmed this is
now working OK.
3. Sort the array of objects on whatever member the user
chooses, ascending or descending; some members are integers,
some are floats, and some are char arrays.

This is the wall. I don't know how to do this. I once wrote
an extensive swap routine in C, but the diskettes have
disappeared. I am retired now and have no access to an
instructor; neither of my C++ books discuss sorting, and
my efforts to apply the sort() and qsort() code I have gathered
from web searches have all failed, as have my efforts to write
my own from 'scratch', as I did 15 years ago.

GAAACCKK! I'm in my fourth day now. I'm not a student, not
doing this for profit, and I basically love programming, when
it's not driving me up the wall. Has anyone got any suggestions?
I will be glad to provide details, i.e., plain, commented code.
Wiglaf

Recommended Answers

All 5 Replies

let's say you have a struct/class of this kind:

struct A
{
  int number ;
  double value ;
  char name[30] ;
};

and you want to sort an array of A s on the member value .
first, write a comparison function that the sort can use which accepts two A s to be compared:

bool compare_on_descending_value( const A& first, const A& second )
{
  // function to compare elements of the sequence
  // return true if first should appear *before* second
  // in the sorted sequence; false otherwise
  // for example, this would sort on descending value (member)
  return first.value > second.value ;
}

then call std::sort (header <algorithm> ) passing the comparison function to tell it how elements should be compared for the sort:

void sort_on_descending_value( A* array, std::size_t num_elements )
{
  // use std::sort from <algorithm>
  std::sort( array, array+num_elements, compare_on_descending_value ) ;
}

Welcome to DaniWeb. Glad to see that another retired person is here.

If you put those classes into a <vector> then you can use std::sort to sort them. All you have to do is write a set of functions that will be called by sort() to return true or false. You would have one of these functions for each data member you want to sort on.

Here is an example of how to use std::sort with an array of classes. About half way down the page you will find this:

struct SAscendingDateSort
{
     bool operator()(CHistoryItem*& rpStart, CHistoryItem*& rpEnd)
     {
          return rpStart->GetTimestamp() < rpEnd->GetTimestamp();
     }
};

And a little further down

// Sort the items in ascending order
     std::sort(HistoryVector.begin(), HistoryVector.end(), 
               SAscendingDateSort());

HistoryVector is a vector of History classes -- vector<Histor> HistoryVector; You might also be able to do this with templates, but I'm not that great with templates so hopefully someone else can help you with that.

[edit]^^^ Good: I see Vijayan had the same idea that I posted.[/edit]

dragon: > You might also be able to do this with templates
yes, if there are a lot of members, templates would provide a generic mechanism.
didn't post this earlier because i didn't want to scare away the OP (having spent some time here, i'm a little wiser now) .

#include <functional>

// compare member variable of type T (class C)
template< typename C, typename T >
struct cmp_mem_var_t : std::binary_function<C,C,bool>
{
  cmp_mem_var_t( T C::*p_mem_var, bool ascend )
    : ptr_mem_var(p_mem_var), ascending(ascend) {}
  bool operator() ( const C& first, const C& second ) const
  {
    return ascending ?
             first.*ptr_mem_var < second.*ptr_mem_var :
             first.*ptr_mem_var > second.*ptr_mem_var ;
  }
  private:
    T C::*ptr_mem_var ;
    bool ascending ;
};

// compare result (type T) of a const member function (class C)
template< typename C, typename T >
struct cmp_mem_fun_t : std::binary_function<C,C,bool>
{
  cmp_mem_fun_t( T (C::*p_mem_fun)() const, bool ascend )
    : ptr_mem_fun(p_mem_fun), ascending(ascend) {}
  bool operator() ( const C& first, const C& second ) const
  {
    return ascending ?
             (first.*ptr_mem_fun)() < (second.*ptr_mem_fun)() :
             (first.*ptr_mem_fun)() > (second.*ptr_mem_fun)() ;
  }
  private:
    T (C::*ptr_mem_fun)() const ;
    bool ascending ;
};

// two helpers to deduce types (syntactic sugar)
template< typename C, typename T > inline cmp_mem_var_t<C,T>
compare_member( T C::*p_mem_var, bool ascending = true )
{ return cmp_mem_var_t<C,T>( p_mem_var, ascending ) ; }

template< typename C, typename T > inline cmp_mem_fun_t<C,T>
compare_member( T (C::*p_mem_fun)() const, bool ascending = true )
{ return cmp_mem_fun_t<C,T>( p_mem_fun, ascending ) ; }

and this is how it could be used:

#include <algorithm>

struct A
{
  int fun_one() const { return number % 100 ; }
  double fun_two() const { return value - number ; }
  int number ;
  double value ;
};

struct B
{
  float value() const { return 1000.0 - flt ; }
  float flt ;
};

int main()
{
  enum { N = 10 }; A a[N] ; B b[N] ;

  std::sort( a, a+N, compare_member(&A::number) ) ;
  std::sort( a, a+N, compare_member( &A::value, false ) ) ;
  std::sort( b, b+N, compare_member(&B::flt) ) ;

  std::sort( a, a+N, compare_member( &A::fun_one, false ) ) ;
  std::sort( a, a+N, compare_member(&A::fun_two) ) ;
  std::sort( b, b+N, compare_member(&B::value) ) ;
}

let's say you have a struct/class of this kind:

struct A
{
  int number ;
  double value ;
  char name[30] ;
};

and you want to sort an array of A s on the member value .
first, write a comparison function that the sort can use which accepts two A s to be compared:

bool compare_on_descending_value( const A& first, const A& second )
{
  // function to compare elements of the sequence
  // return true if first should appear *before* second
  // in the sorted sequence; false otherwise
  // for example, this would sort on descending value (member)
  return first.value > second.value ;
}

then call std::sort (header <algorithm> ) passing the comparison function to tell it how elements should be compared for the sort:

void sort_on_descending_value( A* array, std::size_t num_elements )
{
  // use std::sort from <algorithm>
  std::sort( array, array+num_elements, compare_on_descending_value ) ;
}

My attempts to implement Vijayan121's solution is generating
incomprehensible (to me) compiler errors. Let me show you how
I tried to implement the solution, which should isolate my mistakes.

1. This is the class I am using, which is included as a header in the
main program:

class LakeDataClass
{
public:
char DTG[13];
float DepthOfMeasurements;
char WaveDirectionStrength[5];
char Weather[9];
float DissolvedOxygen;
float pH;
float AirTempCelsius;
float WaterTempCelsius;
float WaterTempFahrenheit;
float AirTempFahrenheit;
float SunLight;
float BarPress;
};

Initial attempts to sort on the character array DTG failed so
badly I switched to the relatively simple float var 'pH'.

2. The class is then used to instantiate copies of itself into a global
array (LakeDataArray), and a temporary holder for an individual object/class
('entry') is initialized with zeroes.

LakeDataClass * LakeDataArray[13];
LakeDataClass entry = {0};

The user chooses how many objects he wants to create, and the program then
successfully gathers data from him and writes each object as a binary object
into a disk file. All of this has been confirmed to work fine.

3. Now I want to sort the data in the disk file, and this is where I have
encountered problems I can't solve. Here is how I have implemented Vijayan121's
solution:

a. First, PROTOTYPE the two functions before main():

bool compare_on_descending_value(const LakeDataClass& first,
const LakeDataClass& second);

void sort_on_descending_value(const LakeDataClass * array, int);

b. Second, DEFINE the two functions after main():

bool compare_on_descending_value( const LakeDataClass& first,
const LakeDataClass& second )
{
return first.pH > second.pH;
}

void sort_on_descending_value( const LakeDataClass *, sizeof(LakeDataClass->DTG))
{
std::sort (LakeDataArray, LakeDataArray+ObjectReadCount, compare_on_descending_value);
}

c. And third, CALL the function from within main():

sort_on_descending_value(LakeDataClass * LakeDataArray, sizeof(LakeDataArray[]->DTG,
compare_on_descending_value( LakeDataClass& first, LakeDataClass& second ));

I will not include the compiler errors, because reviewers might be able
in one look to see what mistake(s) I am making. I appreciate any help that can be
offered. Wiglaf.

#include <algorithm>

class LakeDataClass
{
  public:
    char DTG[13];
    float DepthOfMeasurements;
    char WaveDirectionStrength[5];
    char Weather[9];
    float DissolvedOxygen;
    float pH;
    float AirTempCelsius;
    float WaterTempCelsius;
    float WaterTempFahrenheit;
    float AirTempFahrenheit;
    float SunLight;
    float BarPress;
};

bool compare_on_descending_value( const LakeDataClass& first,
                                  const LakeDataClass& second);

// can't modify const things! remove the const specifier
void sort_on_descending_value( /*const*/ LakeDataClass* array, int N );


int main()
{
  const int MAXSZ = 1000 ;
  LakeDataClass LakeDataArray[MAXSZ] ;
  int ObjectReadCount = 0 ;

  // fill up array here
  // increment ObjectReadCount for each object read

  // to sort the array:
  sort_on_descending_value( LakeDataArray, ObjectReadCount ) ;
  // use sorted array
}

bool compare_on_descending_value( const LakeDataClass& first,
                                  const LakeDataClass& second )
{
  return first.pH > second.pH;
}


void sort_on_descending_value( /*const*/ LakeDataClass* array, int N )
{
   std::sort ( array, array+N, compare_on_descending_value );
}

> attempts to sort on the character array DTG failed .,..
write the comparison function this way:

#include <cstring>
bool compare_on_asscending_value( const LakeDataClass& first,
                                  const LakeDataClass& second )
{
  return std::strcmp( first.DTG, second.DTG ) < 0 ;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.