Sort Based on Multiple Things in C++

Sort based on multiple things in C++

bool CompareData(const int& A, const int& B)
{
return (Records[A].Age < Records[B].Age) ||
((Records[A].Age == Records[B].Age) && (Records[A].Gender > Records[B].Gender)) ||
((Records[A].Age == Records[B].Age) && (Records[A].Gender == Records[B].Gender) &&
(strcmp(Records[A].Surname, Records[B].Surname) < 0));
}

This compares first by age and returns true if A should appear before B based on age.

If ages are equal, it then compares by gender, and returns true if A should appear before B based on gender (A is female and B is male).

If ages are equal and genders are equal, it then compares by surname (using strcmp, although if you had used std::string instead of a char array, you could have just used <), and returns true if A should appear before B alphabetically by surname.

Is there a way to sort structs by multiple variables in C?

Use the standard function qsort declared in the header <stdlib.h> and write a user-defined comparison function.

Here you are.

#include <stdio.h>
#include <stdlib.h>

#define MAX_USERNAME_LENGTH 10

typedef struct
{
char username[MAX_USERNAME_LENGTH];
unsigned int rides;
unsigned int rank;
} driver;

int cmp( const void *left, const void *right )
{
const driver *a = ( const driver *)left;
const driver *b = ( const driver *)right;

if ( b->rank < a->rank )
{
return -1;
}
else if ( a->rank < b->rank )
{
return 1;
}
else
{
return ( a->rides < b->rides ) - ( b->rides < a->rides );
}
}

int main(void)
{
enum { N = 4 };
driver driver_list[N] =
{
{ "frank209", 3, 6 },
{ "john76", 7, 6 },
{ "harry99", 2, 2 },
{ "bob77", 5, 2 }
};

qsort( driver_list, N, sizeof( driver ), cmp );

for ( size_t i = 0; i < N; i++ )
{
printf( "%s, %u, %u\n",
driver_list[i].username, driver_list[i].rides, driver_list[i].rank );
}

return 0;
}

The program output is

john76, 7, 6
frank209, 3, 6
bob77, 5, 2
harry99, 2, 2

Sorting structs based on multiple conditions?

The solution is pretty simple:

std::stable_sort(entries.begin(), entries.end(),
[] (const Entry *lhs, const Entry *rhs)
{
if( lhs->count != rhs->count )
return lhs->count > rhs->count;
else
return lhs->word > rhs->word;
});

C++ Sorting an array with multiple value types using a single function

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

Here is an example:

struct A{
int a1;
int a2;
string a3;
};

bool predicate(A const& lhs, A const& rhs) {
if (lhs.a1 != rhs.a1)
return lhs.a1 < rhs.a1;
if (lhs.a2 != rhs.a2)
return lhs.a2 < rhs.a2;
return lhs.a3 < rhs.a3;
}

Or as suggested by @Max you can use std::tie:

bool predicate(A const& lhs, A const& rhs) {
return std::tie(lhs.a1, lhs.a2, lhs.a3) < std::tie(rhs.a1, rhs.a2, rhs.a3);
}

Now, pass that function to your sort call:

std::sort(vectorA.begin(), vectorA.end(), & predicate);

Or to the sort function from your older question:

template <class  T>
void sortArray(T record[]) {

bool swap = true;
while (swap) {
swap = false;
for (size_t i = 0; i < arraySize - 1; i++) {
if (predicate(record[i] ,record[i + 1])) {
T temp = record[i];
record[i] = record[i + 1];
record[i + 1] = temp;
swap = true;
}
}
}
}

How to sort multiple arrays based on one and print them out

Using the techniques used in this answer, you can create an array of indices, and sort the index array based on the criteria you're interested in. Then when referencing the data in a sorted manner, you use the index array.

#include <vector>
//...
std::vector<int> index_array;
int main()
{
for (int i = 0; i < number_of_items; ++i)
index_array.push_back(i);
//...
SelectionSort(city, size)
}

void SelectionSort(string city[], int size)
{
int i;
int j;
int indexSmallest;
string temp;

for (i = 0; i < size; ++i)
{
indexSmallest = i;
for (j = i + 1; j < size; ++j)
{
if (city[index_array[j]] < city[index_array[indexSmallest]])
{
indexSmallest = j;
}
}

temp = index_array[i];
index_array[i] = index_array[indexSmallest];
index_array[indexSmallest] = temp;
}
}

Then when accessing the arrays, use the array of indices:

for (int i = 0; i < size; ++i)
std::cout << city[index_array[i]] << "\n" << names[index_array[i]] << "\n\n";

C++ double sorting data with multiple elements

The struct you have is fine, except that you may want to add an overload of operator< to do comparison. Here I'm doing the "compare by name, then date" comparison:

// Add this as a member function to `entry`.
bool operator<(entry const &other) const {
if (name1 < other.name1)
return true;
if (name1 > other.name1)
return false;

// otherwise name1 == other.name1
// so we now fall through to use the next comparator.

if (date < other.date)
return true;
return false;
}

[Edit: What's required is called a "strict weak ordering". If you want to get into detail about what the means, and what alternatives are possible, Dave Abrahams wrote quite a detailed post on C++ Next about it.

In the case above, we start by comparing the name1 fields of the two. If a<b, then we immediately return true. Otherwise, we check for a>b, and if so we return false. At that point, we've eliminated a<b and a>b, so we've determined that a==b, in which case we test the dates -- if a<b, we return true. Otherwise, we return false -- either the dates are equal, or b>a, either of which means the test for a<b is false. If the sort needs to sort out (no pun intended) which of those is the case, it can call the function again with the arguments swapped. The names will still be equal, so it'll still come down to the dates -- if we get false, the dates are equal. If we get true on the swapped dates, then what started as the second date is actually greater. ]

The operator< you define in the structure defines the order that will be used by default. When/if you want you can specify another order for the sorting to use:

struct byid { 
bool operator<(entry const &a, entry const &b) {
return a.id_number < b.id_number;
}
};

std::vector<entry> entries;

// sort by name, then date
std::sort(entries.begin(), entries.end());

// sort by ID
std::sort(entries.begin(), entries.end(), byid());

Order a List (C#) by many fields?

Use ThenBy:

var orderedCustomers = Customer.OrderBy(c => c.LastName).ThenBy(c => c.FirstName)

See MSDN: http://msdn.microsoft.com/en-us/library/bb549422.aspx



Related Topics



Leave a reply



Submit