Forum Replies Created

Viewing 1 post (of 1 total)
  • Author
    Posts
  • in reply to: Sorting an array with std::set #636699
    Michele di Lascio
    Participant
        Up
        0
        Down
        ::

        Thanks for the hint! I tried using static_cast<double>(e) directly, but that fails because std::string cannot be converted to double at compile time. So, I extended your idea using my previous idea of checking at compile time the type:

        #include <iostream>
        #include <vector>
        #include <variant>
        #include <string>
        #include <algorithm>
        #include <set>
        #include <ranges>
        #include <limits>

        using numberType = std::variant<int, float, double, std::string>;

        template <typename T>
        void printArray(const std::vector<T>& arr) {
            for (const auto& element : arr) {
                std::visit([](auto&& value) {
                    std::cout << value << " ";
                 }, element);
            }
            std::cout << std::endl; // Print a newline after printing all elements
        }

        int main() {

            std::vector<numberType> arr = {5, 8, "apple", 3.2, 6, 2, 3, 7.8f, "4.7", 5, "10", 3.2};

            std::cout << "Unsorted array with mixed types and duplicates: ";
            printArray(arr);

            // Use std::set to ensure uniqueness
            std::set<numberType> uniqueSet(arr.begin(), arr.end());
            // Convert the set back to a vector
            std::vector<numberType> uniqueArr(uniqueSet.begin(), uniqueSet.end());
            std::cout << "Unsorted array with mixed types and no duplicates: ";
            printArray(uniqueArr);

            // Here we use std::ranges::sort to operate on a range with a projection lambda
            std::ranges::sort(uniqueArr, std::less(), [](auto const& x) {
                // apply a lambda function as a visitor to handle the different types contained in the std::variant x
                // the result of the lambda must be double
                return std::visit([](auto const& e) -> double {
                    // compile-time conditional branching to check if two types are the same
                    // use std::decay_t to ensure the type will always be the basic one
                    if constexpr (std::is_same_v<std::decay_t<decltype(e)>, std::string>) {
                        try { // if e is a std::string try if it can be automatically converted to a double
                            return std::stod(e); // Convert numeric strings to double
                        } catch (...) { // otherwise place it at the end of the sorted array
                            return std::numeric_limits<double>::max(); // Non-numeric strings go to the end
                        }
                    } else { // other types can be casted directly
                        return static_cast<double>(e); // For numeric types
                    }
                }, x);
            });

            std::cout << "Sorted array with mixed types: ";
            printArray(uniqueArr);

            return 0;
        }

        Output:
        Unsorted array with mixed types and duplicates: 5 8 apple 3.2 6 2 3 7.8 4.7 5 10 3.2
        Unsorted array with mixed types and no duplicates: 2 3 5 6 8 7.8 3.2 10 4.7 apple
        Sorted array with mixed types: 2 3 3.2 4.7 5 6 7.8 8 10 apple

        This is of course a very elegant solution, but it doesn’t solve the original problem completely. For example, if I were to define my array as follows, std::set won’t consider 3.2 and “3.2” as the same element: std::vector<numberType> arr = {5, 8, "apple", 3.2, 6, 2, 3, 7.8f, "4.7", 5, "10", "3.2"}. Moreover, I don’t like the fact that std::set is not preserving the original order of the elements of the input array. In fact, I’d like to have 5 8 apple 3.2 6 2 3 7.8 4.7 10.

        By using again the struct Compare I could handle the problem by defining a custom operator for std::set. But the code would be tedious and ugly. Any suggestion and/or improvements on the implementation above?

      Viewing 1 post (of 1 total)