Tag Archives: multiple property sort
C++ || How To Sort An Array/Vector/Container With Multiple Sorting Conditions Using C++
The following is a module with functions which demonstrates how to sort an array/vector/container with multiple sorting conditions using C++.
The function demonstrated on this page is a wrapper for the std::sort function, which means it works for any container supported by std::sort.
This function accepts multiple sorting conditions (comparison functions), which allows for complex array sorting much like the SQL/LINQ ‘Order By’ operation.
1. Simple Array – Ascending
The example below demonstrates the use of Utils::sortBy to sort a simple array.
In this example, no sorting conditions are specified. In this case, the array is sorted in ascending order.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// Simple Array - Ascending // Declare array int arry[] = { 1987, 19, 22, 2009, 2019, 1991, 28, 31 }; // Get array size int size = sizeof(arry) / sizeof(arry[0]); // Sort array in default ascending order Utils::sortBy(arry, arry + size); // Display results for (int index = 0; index < size; ++index) { std::cout << arry[index] << std::endl; } // expected output: /* 19 22 28 31 1987 1991 2009 2019 */ |
2. Simple Array – Descending
The example below demonstrates the use of Utils::sortBy to sort a simple array.
In this example, a sorting condition (comparison function) is specified. In this case, the array is sorted in descending order.
Note: In the example below, a lambda is used, though it is not required. A regular function can be used here as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// Simple Array - Descending // Declare array int arry[] = { 1987, 19, 22, 2009, 2019, 1991, 28, 31 }; // Get array size int size = sizeof(arry) / sizeof(arry[0]); // Declare sort condition auto condition = [](const auto& lhs, const auto& rhs) { return lhs > rhs; }; // Sort array in descending order Utils::sortBy(arry, arry + size, condition); // Display results for (int index = 0; index < size; ++index) { std::cout << arry[index] << std::endl; } // expected output: /* 2019 2009 1991 1987 31 28 22 19 */ |
3. Object Vector – Multi Key Sort
The example below demonstrates the use of Utils::sortBy to sort an object vector.
In this example, multiple sorting conditions (comparison functions) are specified. In this case, the vector is sorted by multiple object properties.
When multiple sorting conditions are specified, the sequence is sorted in the order in which the conditions are supplied (FIFO).
Note: In the example below, lambda functions are used, though they are not required. Regular functions can be used here as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// Object Vector - Multi Key Sort // Declare object struct Person { int id; std::string name; }; // Declare data std::vector<Person> people = { {31, "Kenneth"}, {28, "Jennifer"}, {87, "Lynn"}, {91, "Sole"}, {22, "Kenneth"}, {19, "Jennifer"} }; // Sort vector by name length ASC, id DESC Utils::sortBy(people.begin(), people.end(), { [](const auto& lhs, const auto& rhs) { return lhs.name.length() < rhs.name.length(); }, [](const auto& lhs, const auto& rhs) { return lhs.id > rhs.id; } }); // Display results for (const auto& person : people) { std::cout << person.id << " - " << person.name << std::endl; } // expected output: /* 91 - Sole 87 - Lynn 31 - Kenneth 22 - Kenneth 28 - Jennifer 19 - Jennifer */ |
4. Utils Namespace
The following is the Utils Namespace. Include this in your project to start using!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
// ============================================================================ // Author: Kenneth Perkins // Date: Mar 8, 2021 // Taken From: http://programmingnotes.org/ // File: Utils.h // Description: Handles general utility functions // ============================================================================ #pragma once #include <algorithm> #include <functional> #include <type_traits> #include <iterator> #include <vector> namespace Utils { /** * FUNCTION: evaluate * USE: Evaluates each sorting condition and determines the order the item should be in * @param conditions: The comparison functions by which the sequence should be sorted * @param lhs: The first element for comparison * @param rhs: The second element for comparison * @return: The sorting order of this item */ template<typename T> bool evaluate(const std::vector<std::function<bool(T, T)>>& conditions, const T& lhs, const T& rhs) { bool result = false; // Evaluate each condition based on the order they were supplied in for (const auto& condition : conditions) { // Call the comparison function to evaluate the condition if (condition(lhs, rhs)) { result = true; break; } else if (condition(rhs, lhs)) { break; } } return result; } /** * FUNCTION: sortBy * USE: Sorts a sequence in ascending or descending order depending on the sorting conditions * @param first: The first position of the sequence to be sorted * @param last: The last position of the sequence to be sorted * @param conditions: The comparison functions by which the sequence should be sorted. * Accepts multiple comparison functions. The sequence is sorted in the * order in which the conditions were placed (FIFO) * @return: N/A */ template<typename RandomIt, typename T = typename std::iterator_traits<RandomIt>::value_type> void sortBy(RandomIt first, RandomIt last, const std::vector<typename std::common_type<std::function<bool(T, T)>>::type>& conditions) { std::sort(first, last, [&](const T& lhs, const T& rhs) { return evaluate(conditions, lhs, rhs); }); } /** * FUNCTION: sortBy * USE: Sorts a sequence in ascending or descending order depending on the sorting condition * @param first: The first position of the sequence to be sorted * @param last: The last position of the sequence to be sorted * @param condition: A comparison function by which the sequence should be sorted * @return: N/A */ template<typename RandomIt, typename T = typename std::iterator_traits<RandomIt>::value_type> void sortBy(RandomIt first, RandomIt last, const typename std::common_type<std::function<bool(T, T)>>::type& condition) { std::vector<std::function<bool(T, T)>> conditions = { condition }; sortBy(first, last, conditions); } /** * FUNCTION: sortBy * USE: Sorts a sequence in ascending order * @param first: The first position of the sequence to be sorted * @param last: The last position of the sequence to be sorted * @return: N/A */ template<typename RandomIt, typename T = typename std::iterator_traits<RandomIt>::value_type> void sortBy(RandomIt first, RandomIt last) { auto condition = [](const T& lhs, const T& rhs) { return lhs < rhs; }; sortBy(first, last, condition); } }// http://programmingnotes.org/ |
5. More Examples
Below are more examples demonstrating the use of the ‘Utils‘ Namespace. Don’t forget to include the module when running the examples!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
// ============================================================================ // Author: Kenneth Perkins // Date: Mar 8, 2021 // Taken From: http://programmingnotes.org/ // File: program.cpp // Description: The following demonstrates the use of the Utils Namespace // ============================================================================ #include <iostream> #include <string> #include <exception> #include <vector> #include <utility> #include "Utils.h" void display(const std::string& message); int main() { try { // Declare array int arry[] = { 1987, 19, 22, 2009, 2019, 1991, 28, 31 }; // Get array size int size = sizeof(arry) / sizeof(arry[0]); // Sort array in default ascending order Utils::sortBy(arry, arry + size); // Display results for (int index = 0; index < size; ++index) { std::cout << arry[index] << std::endl; } display(""); // Declare sort condition auto condition = [](const auto& lhs, const auto& rhs) { return lhs > rhs; }; // Sort array in descending order Utils::sortBy(arry, arry + size, condition); // Display results for (int index = 0; index < size; ++index) { std::cout << arry[index] << std::endl; } display(""); // Declare object struct Person { int id; std::string name; }; // Declare data std::vector<Person> people = { {31, "Kenneth"}, {28, "Jennifer"}, {87, "Lynn"}, {91, "Sole"}, {22, "Kenneth"}, {19, "Jennifer"} }; // Sort vector by name length ASC, id DESC Utils::sortBy(people.begin(), people.end(), { [](const auto& lhs, const auto& rhs) { return lhs.name.length() < rhs.name.length(); }, [](const auto& lhs, const auto& rhs) { return lhs.id > rhs.id; } }); // Display results for (const auto& person : people) { std::cout << person.id << " - " << person.name << std::endl; } display(""); struct Student { std::string name; // Given int math; // Marks in math (Given) int phy; // Marks in Physics (Given) int che; // Marks in Chemistry (Given) int total; // Total marks (To be filled) int rank; // Rank of student (To be filled) }; const int n = 5; // array of structure objects Student a[n]; // Details of Student 1 a[0].name = "Bryan"; a[0].math = 80; a[0].phy = 95; a[0].che = 85; // Details of Student 2 a[1].name = "Kevin"; a[1].math = 95; a[1].phy = 85; a[1].che = 99; // Details of Student 3 a[2].name = "Nicky"; a[2].math = 95; a[2].phy = 85; a[2].che = 80; // Details of Student 4 a[3].name = "Steve"; a[3].math = 80; a[3].phy = 70; a[3].che = 90; // Details of Student 5 a[4].name = "Rohan"; a[4].math = 80; a[4].phy = 80; a[4].che = 80; for (int i = 0; i < n; i++) a[i].total = a[i].math + a[i].phy + a[i].che; Utils::sortBy(a, a + n, { [](const auto& lhs, const auto& rhs) { return lhs.math > rhs.math; }, [](const auto& lhs, const auto& rhs) { return lhs.phy > rhs.phy; }, [](const auto& lhs, const auto& rhs) { return lhs.che > rhs.che; } }); for (int i = 0; i < n; i++) a[i].rank = i + 1; // Column names for displaying data std::cout << "Rank" << " " << "Name" << " "; std::cout << "Maths" << " " << "Physics" << " " << "Chemistry"; std::cout << " " << "Total\n"; // Display details of Students for (int i = 0; i < n; i++) { std::cout << a[i].rank << " "; std::cout << a[i].name << " "; std::cout << a[i].math << " " << a[i].phy << " " << a[i].che << " "; std::cout << a[i].total << " "; std::cout << "\n"; } using my_pair = std::pair<double, double>; std::vector<my_pair> data; data.push_back(my_pair(3, 2)); data.push_back(my_pair(1, 2)); data.push_back(my_pair(1, 1)); data.push_back(my_pair(2, 2)); Utils::sortBy(data.begin(), data.end(), { [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; }, [](const auto& lhs, const auto& rhs) { return lhs.second > rhs.second; } }); display(""); for (const auto& p : data) { std::cout << p.first << ' ' << p.second << std::endl; } display(""); struct Node { int x; int y; float value; }; std::vector<Node> vec{ {5, 6, 0.f}, {2, 4, 0.f}, {1, 1, 0.f}, {1, 0, 0.f}, {8, 10, 0.f}, {4, 7, 0.f}, {7, 1, 0.f}, {5, 4, 0.f}, {6, 1, 0.f}, {1, 4, 0.f}, {3, 10, 0.f}, {7, 2, 0.f} }; Utils::sortBy(vec.begin(), vec.end(), { [](const Node& lhs, const Node& rhs) { return lhs.y < rhs.y; }, [](const Node& lhs, const Node& rhs) { return lhs.x < rhs.x; } }); std::cout << "x y" << std::endl << std::endl; for (const auto& item : vec) { std::cout << item.x << " " << item.y << std::endl; } } catch (std::exception& e) { display("\nAn error occurred: " + std::string(e.what())); } std::cin.get(); return 0; } void display(const std::string& message) { std::cout << message << std::endl; }// http://programmingnotes.org/ |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.