Multi-column sort (urgent help needed)

D

Dr. Ann Huxtable

Hello All,

I am reading a CSV (comma seperated value) file into a 2D array. I want
to be able to sort multiple columns (ala Excel), so I know for starters,
I cant be using the array, I need something more sophistictated like a
vector of row objects.

The data is of this format (same number of columns for each row):

A, x, y, z, ...
A, b, c, f, ...
A, s, b, m, ...
C, p, s, w, ...
C, a, s, u, ....

etc ...

Esentially, what I want to do is :

1). Read the data into memory (no brainer - I can do that)
2). Sort the data by specified columns (say column 2, and 4)

I would be very grateful if any one could show me how to do this using a
simple code example, or point me to a URL for some examples, or better
still point me to a library that is capable of doing this.

Many thanks in advance for your help

Ann
 
S

Shailesh Humbad

You could use a public domain database library like
http://www.sqlite.org. "SQLite is a small C library that implements a
self-contained, embeddable, zero-configuration SQL database engine."
 
P

Phlip

Dr. Ann Huxtable said:
I am reading a CSV (comma seperated value) file into a 2D array. I want
to be able to sort multiple columns (ala Excel), so I know for starters,
I cant be using the array, I need something more sophistictated like a
vector of row objects.

The data is of this format (same number of columns for each row):

A, x, y, z, ...
A, b, c, f, ...
A, s, b, m, ...
C, p, s, w, ...
C, a, s, u, ....

etc ...

Esentially, what I want to do is :

1). Read the data into memory (no brainer - I can do that)
2). Sort the data by specified columns (say column 2, and 4)

I would be very grateful if any one could show me how to do this using a
simple code example, or point me to a URL for some examples, or better
still point me to a library that is capable of doing this.

Look up the std::sort algorithm in the C++ Standard Library.
 
J

Jon Bell

I am reading a CSV (comma seperated value) file into a 2D array. I want
to be able to sort multiple columns (ala Excel), so I know for starters,
I cant be using the array, I need something more sophistictated like a
vector of row objects.

Yes, a vector of struct or class objects that represent rows, would be
more appropriate for this.
2). Sort the data by specified columns (say column 2, and 4)

You need to supply a custom comparison function to the standard sort()
function. Here's an example that I gave my students last year. Each
comparison function sorts by one field (column) only; to sort by more than
one field together, expand the comparison logic in the
function accordingly.

// profsort.cpp
//
// Demonstrates how to sort a vector of classes by supplying (a) a
// comparision function or (b) a comparison function object to the
// standard sort() function.
//----------------------------------------------------------------------

#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

//---------------------------------------------------------------------
// a simple class for storing data about professors

class Professor
{
public:
Professor (const string& initFN, const string& initLN,
const string& initOffice);
void Display() const;
friend int CompareByLastName (const Professor& lhs,
const Professor& rhs);
friend class CompareByOffice;
private:
string lastName, firstName, office;
};

// Constructor

Professor::professor (const string& initFN, const string& initLN,
const string& initOffice)
: lastName(initLN), firstName(initFN), office(initOffice) {}

// A simple one-line display

void Professor::Display() const
{
cout << setw (15) << lastName
<< setw (10) << firstName
<< setw (20) << office
<< '\n';
}

// Comparison function for sorting by last name; it needs to
// be a friend function so it can access private data of the class

int CompareByLastName (const Professor& lhs, const Professor& rhs)
{
return (lhs.lastName < rhs.lastName);
}

// Here's another way to set up the comparison: a function object.
// This one compares by office location. This class needs to be
// a friend class of Professor so it can use private data.

class CompareByOffice
{
public:
int operator () (const Professor& lhs, const Professor& rhs)
{ return (lhs.office < rhs.office); };
};

//----------------------------------------------------------------------

void DisplayVector (const vector<Professor>& profs)
{
cout << '\n';
for (int k = 0; k < profs.size(); ++k)
{
profs[k].Display();
}
}

//----------------------------------------------------------------------
//----------------------------------------------------------------------

int main ()
{
ifstream profsfile ("profs.dat");
vector<Professor> profs;

// File format is one professor per line, with the fields separated
// by tabs

string firstName, lastName, office;
while (getline (profsfile, firstName, '\t')
&& getline (profsfile, lastName, '\t')
&& getline (profsfile, office, '\n'))
{
profs.push_back (Professor (firstName, lastName, office));
}
profsfile.close ();

cout << "\nBefore sorting:\n";
DisplayVector (profs);

// sort by last name, using an ordinary function for the comparison

sort (profs.begin(), profs.end(), CompareByLastName);

cout << "\nAfter sorting by last name:\n";
DisplayVector (profs);

// sort by office location, using a function object for the comparison

sort (profs.begin(), profs.end(), CompareByOffice());

cout << "\nAfter sorting by office:\n";
DisplayVector (profs);

cout << '\n';

return 0;
}
 
I

Ivan Vecerina

Jon Bell said:
You need to supply a custom comparison function to the standard sort()
function. Here's an example that I gave my students last year. Each
comparison function sorts by one field (column) only; to sort by more than
one field together, expand the comparison logic in the
function accordingly.

I would like to make a single comment/addition to your (excellent) example.
int CompareByLastName (const Professor& lhs, const Professor& rhs)
{
return (lhs.lastName < rhs.lastName);
} ....
class CompareByOffice
{
public:
int operator () (const Professor& lhs, const Professor& rhs)
{ return (lhs.office < rhs.office); };
};

If one would like to simultaneously sort by two columns (e.g. sort by office
first, but then by name within the same office), one will want to replace
the second call to sort below with std::stable_sort.
sort (profs.begin(), profs.end(), CompareByLastName);

cout << "\nAfter sorting by last name:\n";
DisplayVector (profs);

// sort by office location, using a function object for the comparison

sort (profs.begin(), profs.end(), CompareByOffice());
stable_sort( ...same params... ); // will keep names ordered within
office

Alternatively, a comparison object doing both ordering operations at once
can
be provided to a single sort() call:

int CompareByOfficeAndLastName (const Professor& lhs, const Professor& rhs)
{
return (lhs.office < rhs.office)
|| ( !(rhs.office < lhs.office) && (lhs.lastName <
rhs.lastName) );
// return result of name compare if office compare does not provide an
order
}



hth -Ivan
 
D

Dr. Ann Huxtable

Jon said:
Dr. Ann Huxtable said:
I am reading a CSV (comma seperated value) file into a 2D array. I want
to be able to sort multiple columns (ala Excel), so I know for starters,
I cant be using the array, I need something more sophistictated like a
vector of row objects.


Yes, a vector of struct or class objects that represent rows, would be
more appropriate for this.

2). Sort the data by specified columns (say column 2, and 4)


You need to supply a custom comparison function to the standard sort()
function. Here's an example that I gave my students last year. Each
comparison function sorts by one field (column) only; to sort by more than
one field together, expand the comparison logic in the
function accordingly.

// profsort.cpp
//
// Demonstrates how to sort a vector of classes by supplying (a) a
// comparision function or (b) a comparison function object to the
// standard sort() function.
//----------------------------------------------------------------------

#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

//---------------------------------------------------------------------
// a simple class for storing data about professors

class Professor
{
public:
Professor (const string& initFN, const string& initLN,
const string& initOffice);
void Display() const;
friend int CompareByLastName (const Professor& lhs,
const Professor& rhs);
friend class CompareByOffice;
private:
string lastName, firstName, office;
};

// Constructor

Professor::professor (const string& initFN, const string& initLN,
const string& initOffice)
: lastName(initLN), firstName(initFN), office(initOffice) {}

// A simple one-line display

void Professor::Display() const
{
cout << setw (15) << lastName
<< setw (10) << firstName
<< setw (20) << office
<< '\n';
}

// Comparison function for sorting by last name; it needs to
// be a friend function so it can access private data of the class

int CompareByLastName (const Professor& lhs, const Professor& rhs)
{
return (lhs.lastName < rhs.lastName);
}

// Here's another way to set up the comparison: a function object.
// This one compares by office location. This class needs to be
// a friend class of Professor so it can use private data.

class CompareByOffice
{
public:
int operator () (const Professor& lhs, const Professor& rhs)
{ return (lhs.office < rhs.office); };
};

//----------------------------------------------------------------------

void DisplayVector (const vector<Professor>& profs)
{
cout << '\n';
for (int k = 0; k < profs.size(); ++k)
{
profs[k].Display();
}
}

//----------------------------------------------------------------------
//----------------------------------------------------------------------

int main ()
{
ifstream profsfile ("profs.dat");
vector<Professor> profs;

// File format is one professor per line, with the fields separated
// by tabs

string firstName, lastName, office;
while (getline (profsfile, firstName, '\t')
&& getline (profsfile, lastName, '\t')
&& getline (profsfile, office, '\n'))
{
profs.push_back (Professor (firstName, lastName, office));
}
profsfile.close ();

cout << "\nBefore sorting:\n";
DisplayVector (profs);

// sort by last name, using an ordinary function for the comparison

sort (profs.begin(), profs.end(), CompareByLastName);

cout << "\nAfter sorting by last name:\n";
DisplayVector (profs);

// sort by office location, using a function object for the comparison

sort (profs.begin(), profs.end(), CompareByOffice());

cout << "\nAfter sorting by office:\n";
DisplayVector (profs);

cout << '\n';

return 0;
}


Thanks very much Jon, this is just what I needed !
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,181
Messages
2,570,970
Members
47,536
Latest member
VeldaYoung

Latest Threads

Top