1

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?

Yen Dang
  • 268
  • 2
  • 9
  • offtopic: `using namespace std` in header is big code issue! I see this between lines, since in class declaration (which should be in header), there is `pair` without `std::`! Detailed description [namespace in header](https://stackoverflow.com/a/5849668/1387438) and [usign namespace std;](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). – Marek R Jun 20 '21 at 07:24
  • @MarekR, Thanks for pointing out. I will notice this. – Yen Dang Jun 20 '21 at 09:19

3 Answers3

3

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.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Hi, I tried your code but when sorting "1","3","10","7","8" the return result is "1","10","3","7","8". I want it to work implicitly with numbers too. – Yen Dang Jun 20 '21 at 09:18
  • 1
    Your code doesn't do this well either. Even when invalid use of `std::wcsncmp` is fixed. Anyway see my edit and implementation. If you need use `CString` just provide conversion operator to `std::string_view`. – Marek R Jun 23 '21 at 15:11
  • Hi, Thank you! I learned something new from your code. i figured your approach, i want to ask you small mistake here are you talking about decimals? I would like to know its scope so I can improve it when I can :) – Yen Dang Jun 24 '21 at 03:58
  • Hi @Marek, not sure, my guess is `return asNumberLess(a.prefix, b.prefix);` .Please correct your answer! thanks. – Yen Dang Jun 24 '21 at 04:36
  • 1
    problem are leading zeros for example: `A 001` vs `A 2` https://godbolt.org/z/q57KKcTdE . Other issue is how to threat white characters - but depends on requirements. – Marek R Jun 24 '21 at 06:01
  • thanks you. I got it now. although this is not occur in my data but I will note. – Yen Dang Jun 24 '21 at 06:39
2

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.

273K
  • 29,503
  • 10
  • 41
  • 64
-2

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.