views:

1922

answers:

5

Hi, I am having a hard time with this problem which requires a sort of customer names, customer ids, and finally amount due. I have the whole program figured, but cannot figure out the last prototype needed to do the sorting. i have a struct called Customers, and i will provide the int main() part also. I just need any help to gt started on the prototype SortData().

struct Customers {
    string Name;
    string Id;
    float OrderAmount;
    float Tax;
    float AmountDue;
};

const int MAX_CUSTOMERS = 1000;
bool MoreCustomers(int);
Customers GetCustomerData();
void OutputResults(Customers [], int);
void SortData(const int, const int, Customers []);

int main() {
    Customers c[MAX_CUSTOMERS]; 
    int Count = 0;  
    do {
      c[Count++] = GetCustomerData();   
    } while (MoreCustomers(Count));  


    for (int i = 0; i < Count; i++) {
     c[i].Tax = 0.05f * c[i].OrderAmount;  
     c[i].AmountDue = c[i].OrderAmount + c[i].Tax; 
    }

    SortData(0, Count, c);    //0:Sorts by customer name  
    OutputResults(c, Count);   
    GeneralSort(1, Count, c); //1:Sorts by ID  
    OutputResults(c, Count);  
    GeneralSort(2, Count, c); //2: Sorts by amount due  
    OutputResults(c, Count);  

    return 0;      
}


void SortData(const int SortItem, const int count, CustomerProfile c[]) {
     //0: Sort by name
    //1: Sort by ID
    //3: Sort by amount due
}
+1  A: 
Uri
+5  A: 

You should use C++'s standard sort function, std::sort, declared in the <algorithm> header.

When you sort using a custom sorting function, you have to provide a predicate function that says whether the left-hand value is less than the right-hand value. So if you want to sort by name first, then by ID, then by amount due, all in ascending order, you could do:

bool customer_sorter(Customer const& lhs, Customer const& rhs) {
    if (lhs.Name != rhs.Name)
        return lhs.Name < rhs.Name;
    if (lhs.Id != rhs.Id)
        return lhs.Id < rhs.Id;
    return lhs.AmountDue < rhs.AmountDue;
}

Now, pass that function to your sort call:

std::sort(customers.begin(), customers.end(), &customer_sorter);

This assumes you have an STL container (and not an array, like you have in your sample code) called customers containing customers.

Chris Jester-Young
+2  A: 

You only need to write a comparison function that compares two CustomerProfile types. Once you have this function, you can use either the STL sort (see http://www.sgi.com/tech/stl/sort.html or http://msdn.microsoft.com/en-us/library/ecdecxh1(VS.80).aspx) or the old C qsort: http://en.wikipedia.org/wiki/Qsort_(C_Standard_Library). I would advise against writing your own sort algorithm, unless this is a homework assignment. Your comparison depends on the technology you like to use, it could look do something like this:

int CompareCustomerProfile(
   const CustomerProfile* pC1,
   const CustomerProfile* pC2)
{
 int result = strcmp(pC1->name, pC2->name);
 if (0 != result) return result; 

  result = strcmp(pC1->ID, pC2->ID);
  if (0 != result) return result;

  if (pC1->amountDue < pC2->amountDue) return -1;
 if (pC1->amountDue > pC2->amountDue) return 1;

  return 0
}

this assumes that the 'string' type in your example is a char*. If you use Unicode or multibyte types then the appropriate Unicode or multibyte comparison has to be used, obviously. Then you would just call the algorithm, with your comparison function. Eg. using qsort:

qsort(c, Count, sizeof(CustomerProfile), CompareCustomerProfiler).

Now if this is a homework assignment, you shouldn't be asking here how to do it...

Remus Rusanu
+1  A: 

Its often overlooked that you can actually use STL range functions with C based arrays, like in your example. So you don't actually have to move over to using an STL based container (I won't debate the merits of doing that here :-)).

So, building on the answer from Chris, you could invoke sort as follows:

std::sort( customers, customers+Count, &customer_sorter);
CodeBuddy
A: 

I assume that you are new to programming or in C++, so here is what you probably are looking for:

#include <search.h> // for the qsort()

int
CompareByName( const void *elem1, const void *elem2 )
{
  return ((Customers*)elem1)->Name > ((Customers*)elem2)->Name? 1 : -1;
}

int
CompareByOrderAmount( const void *elem1, const void *elem2 )
{
  return ((Customers*)elem1)->OrderAmount > ((Customers*)elem2)->OrderAmount? 1 : -1;
}

void SortData( int SortItem, int count, Customers customers[] )
{
  switch (SortItem) {
  case 0:
    qsort(customers, count, sizeof(Customers), CompareByName);
    break;
  case 1:
    qsort(customers, count, sizeof(Customers), CompareByOrderAmount);
    break;
  // ...
  }
}

void test()
{
  Customers cust[10];

  cust[0].Name = "ten";
  cust[1].Name = "six";
  cust[2].Name = "five";
  SortData( 0, 3, cust );
  cout << cust[0].Name << endl;
  cout << cust[1].Name << endl;
  cout << cust[2].Name << endl;
}
Nick D
Your answer is distinctly a C-style answer, with no C++ qualities to it (except for the use of the overloaded > operator for strings). If this were a C question (and you changed the string comparison to be strcmp), your answer would be useful, but the way it is, it's not useful for the question at all. For starters, in C++ style, sorting should be using std::sort, not qsort. (BTW, even in using qsort, your comparison function must handle the case when two elements are equal, and return 0.)
Chris Jester-Young
Yes you are right. But using plain struct is also C-style. Using STL maybe is a bit cryptic for starters. Anyway, I have no problem to delete my answer.
Nick D
My comparison function should handle the case of equal elements, true. However, that case is rare and the actual problem is that when we sort arrays it is better to use arrays of pointers and not arrays of structures. So any *good* answer is subjective.
Nick D
Agree about not having containers of whole structures, to make the sort less expensive. I can't speak about idiomatic use of arrays in C++, but it's discouraged to use (bare) pointers in STL containers, because object lifetime is harder to track that way. (shared_ptr is recommended when pointers are desired, e.g., to avoid slicing, or to prevent lots of object copying (like this case), or when used with an uncopyable type.)
Chris Jester-Young
Actually, on that note, AFAIK qsort is usable only with POD types (the standard seems to be silent on this topic, but Googling "can qsort be used with non-pod types" is revealing). The OP's example uses some non-POD types (std::string, in particular) in the struct, so this is another argument in favour of holding pointers instead of whole objects. (However, smart pointers like shared_ptr are not POD types either, so using qsort is generally not recommended, regardless.)
Chris Jester-Young
For reference: Later revisions of the C++ standard are not so silent on whether qsort is usable with non-POD types: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2062.html
Chris Jester-Young