yendang9423082
yendang9423082

Reputation: 365

How to sort vector of class contain CString?

I declared a class like this:

class myclass{
     array myarr;
     pair<PT3D,PT3D> mypair;
     ID myid;
     CString tag;
}

after fill data, i have a vector<myclass> myvec;

How can I sort this vector based on the CString value of each class?

bool SortCompare(const wchar_t* a, const wchar_t* b)
{
    if (wcslen(a) == wcslen(b))
    {
      int k = (int)wcslen(a);
      return std::wcsncmp(a, b, k);
    }
    else
      return wcslen(a) < wcslen(b);
}

 sort(myvec.begin(), myvec.end(), [h](myclass& a,
    myclass& b) {
        return SortCompare(a.tag, b.tag);
    });

However this doesn't work properly , my desired result is a list sorted by human sort as this post.

but I don't know how to use CSortStringArray::CompareAndSwap function, how to use this code with std::sort?

How can I correct my codes?

Upvotes: 1

Views: 222

Answers (3)

Marek R
Marek R

Reputation: 38092

Note CString provides less operator so you do not have to fall back to C-API like wcsncmp.

You are making this overcomplicated.

using C++11:

std::sort(myvec.begin(), myvec.end(), [](const myclass& a, const myclass& b) {
        return a.tag < b.tag; 
    });

C++20 has even something simpler called projection:

std::ranges::sort(myvec, {}, &myclass::tag);

Now the issue of alphanumeric compare. This can look like this:

struct AlphanumericSplitResult {
    std::string_view prefix;
    std::string_view digits;
    std::string_view suffix;
};

AlphanumericSplitResult alphanumericSplit(std::string_view s)
{
    auto i = s.find_first_of("0123456789"sv);
    i = i == std::string_view::npos ? s.size() : i;
    auto j = s.find_first_not_of("0123456789"sv, i);
    j = j == std::string_view::npos ? s.size() : j;
    return { s.substr(0, i), s.substr(i, j - i), s.substr(j) };
}

bool asNumberLess(std::string_view l, std::string_view r)
{
    return l.size() != r.size() ? l.size() < r.size() : l < r;
}

bool alphanumeric_less(std::string_view l, std::string_view r)
{
    if (l.empty())
        return !r.empty();

    auto a = alphanumericSplit(l);
    auto b = alphanumericSplit(r);

    if (a.prefix != b.prefix)
        return a.prefix < b.prefix;
    if (a.digits != b.digits)
        return asNumberLess(a.digits, b.digits);

    return alphanumeric_less(a.suffix, b.suffix);
}

It passes all test I wrote: https://godbolt.org/z/hdG6fq9sa
and it is easy to feed to both algorithms.

Disclaimer: there is small bug in implementation - can you find it? Depending on requirements there are more small issues.

Upvotes: 3

sucksatnetworking
sucksatnetworking

Reputation: 92

In your else, you return Len(a) < Len( b) but this is not the same as Len(a) != Len(b). I would just return false in the else block since you know they aren't the same at that point.

Upvotes: -2

3CxEZiVlQ
3CxEZiVlQ

Reputation: 38784

std::wcsncmp returns 0, > 0 or < 0. > 0 and < 0 are converted to true, 0 to false. Thus, compare "a" with "b" and "b" with "a" both return true. std::sort expects a proper compare function. Perhaps you want return std::wcsncmp(a, b, k) < 0.

Upvotes: 2

Related Questions