Sort structure by last name, then name

I have an algorithm for sorting by last name, but I am having a hard time figuring out how to sort by first name, then if two people have the same first name, sort them by first.

void sortLastName(FRIEND friends[ARRAY_MAX], int& count) {

    FRIEND temp;

    for(int i = 0; i < count - 1; i++) {
        for (int j = i + 1; j < count; j++) {
            if (stricmp(friends[i].lastName, friends[j].lastName) > 0)  {
                temp = friends[i];    //swapping entire struct
                friends[i] = friends[j];
                friends[j] = temp;
            }
        }
    }
}

      

=== EDIT ====================

I don't want to use STD sort()

+1


a source to share


11 answers


Why don't you use std::sort

? What is this for:

struct NameComparer {
  bool operator()(const FRIEND& lhs, const FRIEND& rhs){
    int compareResult = stricmp(lhs.lastName, rhs.lastName);
    if(compareResult == 0){
      compareResult = stricmp(lhs.firstName, rhs.firstName);
    }
    return compareResult < 0;
  }
};

std::sort(friends, friends + ARRAY_MAX, NameComparer());

      



Of course, you really should be using the C ++ class std::string

. What is this for. And then you don't need to curl with error C manipulation functions like stricmp

.

+9


a source


Compare the last names first. If they are equal, compare the first names:



int compareResult = stricmp(friends[i].lastName, friends[j].lastName);
if(compareResult == 0)
    compareResult = stricmp(friends[i].firstName, friends[j].firstName);
if(compareResult < 0)
    // swap friends[i] and friends[j]

      

+5


a source


First, use qsort

or the corresponding C ++ equivalent, which takes a function that compares two objects.

Then the comparison should be trivial:

int compare_by_name(const FRIEND& f1, const FRIEND& f2)
{
    int last_name_matches = strcmpi(f1.lastName, f2.lastName);
    return (last_name_matches != 0) ? last_name_matches :
            strcmpi(f1.firstName, f2.firstName) ;
}

      

NB: A real C ++ implementation will probably use templates for the comparator function.

+4


a source


You must change your comparison. The basic algorithm is if friends [i]> friends [j] then change them. So change your ">" definition to include name comparisons.

Something like the following should do:

if (stricmp(friends[i].lastName, friends[j].lastName) > 0 ||
    (stricmp(friends[i].lastName, friends[j].lastName) == 0 && 
    stricmp(friends[i].firstName, friends[j].firstName) > 0))

      

You might want to only compare names once (store it in temp instead of comparing twice), but the idea is the same.

Note that the "best" way to do this might be to provide comparison functions in the FRIEND class. Then you can use if(friends[i].CompareTo(friends[j]) > 0)

.

+3


a source


In addition to choosing to build a comparison function that uses both names, you can sort by fist names and then sort the names, but you must take care to use a stable sort for the second pass. You can also use it for the first one too.

Good news: std::stable_sort

available and guaranteed to be stable (thanks to Adam and Libt for fixing it). The regular std::sort

and standard c libraries are qsort

not guaranteed to be stable, although there may be some implementation. As Mark points out in the comments, the bubble sort you are showing is already stable.


This is less efficient than selecting one-by-one-sort using the custom-compare-function, but makes it easy to select a user at runtime across multiple views (since you don't have to define every possible comparison function or minilanguage).

+2


a source


Don't do the sort yourself - std :: sort (in <algorithm>

) does the job much better and much more efficiently. (Except you just want to see how your algorithm works for an experimental purpose)

In any case, you will need to specify a comparison function or better a functor.

struct FriendComparer {
  bool operator () (const FRIEND& a, const FRIEND& b) {
      // Comparison code here (see previous posts)
  }
};

      

You can simply call it like this:

std::sort(friendArray, friendArray + count, FriendComparer());

      

+1


a source


If you don't mind using boost.tuple (and replacing or at least modifying an existing Friend implementation) there is a comparison included function.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>

typedef boost::tuple<std::string, std::string> Friend;

Friend f1, f2;
bool compareFriends = f1 < f2;

      

All of the above should work.

+1


a source


Add the following:

else if (stricmp(friends[i].lastName, friends[j].lastName) == 0 &&
         stricmp(friends[i].firstName, friends[j].firstName) > 0) {
    temp = friends[i];    //swapping entire struct
    friends[i] = friends[j];
    friends[j] = temp;
}

      

0


a source


Define a compare function (or class as suggested by jalf) and use STL std :: sort ():

bool compareFriends(FRIEND const & lhs, FRIEND const & rhs)
{
    int const resultLast = stricmp(lhs.lastName, rhs.lastName);

    if(resultLast == 0)
    {
        return stricmp(lhs.firstName, rhs.firstName) < 0;
    }
    else
    {
        return resultLast < 0
    }
}

void sortLastName(FRIEND friends[ARRAY_MAX], int& count)
{
    std::sort(friends, friends + count, &compareFriends);
}

      

0


a source


you can use the concatenation of the left aligned last name and first name as the sort key

this is another point of view you are looking for i think :)

string key(const FRIEND& aFriend)
{
    const int INITIALS_MAX_LENGTH = 200; // assume the worst

    string firstNameKeyPart = string(INITIALS_MAX_LENGTH, ' ');
    string lastNameKeyPart = string(INITIALS_MAX_LENGTH, ' ');

    firstNameKeyPart.replace(0, 0, aFriend.firstName);
    lastNameKeyPart.replace(0, 0, aFriend.lastName);

    return  lastNameKeyPart + firstNameKeyPart;
}

//...

if ( key(friends[i]) > key(friends[j]) )
{
  //swap
}

      

0


a source


You can sort by last name and if the last names match, sort them by first name. Something like this (using Bubble sort):

for (int i = 1; i < dictionary.size(); ++i)
    for (int j = 0; j < dictionary.size()-1; ++j) {
        if (dictionary[i].Last < dictionary[j].Last)
            swap(dictionary[i], dictionary[j]);
    }

for (int i = 1; i < dictionary.size(); ++i)
    for (int j = 0; j < dictionary.size() - 1; ++j) {
        if (dictionary[i].Last == dictionary[j].Last && dictionary[i].First < dictionary[j].First)
            swap(dictionary[i], dictionary[j]);
    }

      

0


a source







All Articles