Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

C++ Sorting elements alphabetically but keeping one always at the beginning

I have elements of the following type stored in a collection.

class Element
{
public:
    bool IsDefault { false };
    std::wstring Name { };

    Element() = default;
    Element(const bool isDefault, std::wstring name) : IsDefault { isDefault }, Name { std::move(name) }
    {}

    bool operator==(const Element& other) const noexcept = default;
};

Note there can only be one element with IsDefault == true.

What I want to achieve is sort the collection alphabetically (case-insensitive), but put the one element with IsDefault == true always at the beginning, regardless of its name.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

My current code works, but I am looking for a way that is more efficient (as it is now, finding the one element with IsDefault == true takes O(N) and then sorting the collection takes O(N log N) afterwards) ore more idiomatic / requires less code. What can I do to improve below code? Is there a way to achieve my goal with a single call to std::ranges::sort or some other function?

I can make use of C++20 features if required.


Current code:

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector elements { Element(false, L"World"), Element(true, L"Foo"), Element(false, L"Zoo"), Element(false, L"Bar") };

    // Find the default element and remove it from the vector.
    Element defaultElement;

    for (const auto& e : elements)
    {
        if (e.IsDefault)
        {
            defaultElement = e;
            std::erase(elements, e);
            break;
        }
    }

    // Sort the remaining elements alphabetically
    std::ranges::sort(elements, [](const Element& a, const Element& b) noexcept
                      {
                          const auto& first { a.Name };
                          const auto& second { b.Name };
                          return ::_wcsnicmp(first.c_str(), second.c_str(), std::min(first.size(), second.size())) < 0;
                      });

    // Insert the default element at index 0
    elements.insert(std::begin(elements), defaultElement);

    _ASSERT(elements.at(0).Name == L"Foo");
    _ASSERT(elements.at(1).Name == L"Bar");
    _ASSERT(elements.at(2).Name == L"World");
    _ASSERT(elements.at(3).Name == L"Zoo");
}

>Solution :

Include the default in the comparison:

if(a.default != b.default)
    return b.default < a.default; // true, if a is true -> a is less

// rest of comparison
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading