c++stringsortingcase-insensitive

Case insensitive sorting of an array of strings


Basically, I have to use selection sort to sort a string[]. I have done this part but this is what I am having difficulty with.

The sort, however, should be case-insensitive, so that "antenna" would come before "Jupiter". ASCII sorts from uppercase to lowercase, so would there not be a way to just swap the order of the sorted string? Or is there a simpler solution?

void stringSort(string array[], int size) {
    int startScan, minIndex;
    string minValue;

    for(startScan = 0 ; startScan < (size - 1); startScan++) {
        minIndex = startScan;
        minValue = array[startScan];

        for (int index = startScan + 1; index < size; index++) {
            if (array[index] < minValue) {
                minValue = array[index];
                minIndex = index;
            }
        }
        array[minIndex] = array[startScan];
        array[startScan] = minValue;
    }
}

Solution

  • C++ provides you with sort which takes a comparison function. In your case with a vector<string> you'll be comparing two strings. The comparison function should return true if the first argument is smaller.

    For our comparison function we'll want to find the first mismatched character between the strings after tolower has been applied. To do this we can use mismatch which takes a comparator between two characters returning true as long as they are equal:

    const auto result = mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), [](const unsigned char lhs, const unsigned char rhs){return tolower(lhs) == tolower(rhs);});
    

    To decide if the lhs is smaller than the rhs fed to mismatch we need to test 3 things:

    1. Were the strings of unequal length
    2. Was string lhs shorter
    3. Or was the first mismatched char from lhs smaller than the first mismatched char from rhs

    This evaluation can be performed by:

    result.second != rhs.cend() && (result.first == lhs.cend() || tolower(*result.first) < tolower(*result.second));
    

    Ultimately, we'll want to wrap this up in a lambda and plug it back into sort as our comparator:

    sort(foo.begin(), foo.end(), [](const unsigned char lhs, const unsigned char rhs){
        const auto result = mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), [](const unsigned char lhs, const unsigned char rhs){return tolower(lhs) == tolower(rhs);});
    
        return result.second != rhs.cend() && (result.first == lhs.cend() || tolower(*result.first) < tolower(*result.second));
    });
    

    This will correctly sort vector<string> foo. You can see a live example here: http://ideone.com/BVgyD2

    EDIT:

    Just saw your question update. You can use sort with string array[] as well. You'll just need to call it like this: sort(array, std::next(array, size), ...