If you have access to the standard library (i.e. any Arduino board except AVR), you can use std::min_element
to find the index of the smallest element, and std::partial_sort
to find the three largest elements. If you want access to the indices of these largest elements, you can use std::partial_sort_copy
and iterate over the indices:
// Return the indices of the N largest elements in the array
template <size_t N, class T, size_t ArraySize>
std::array<size_t, N> max_n_elements(const std::array<T, ArraySize> &array) {
static_assert(N <= ArraySize, "Out of bounds");
// Check if the element at index a is greater than the element at index b
auto compare = [&array](size_t a, size_t b) { return array[a] > array[b]; };
// Result variable to store indices of largest elements
std::array<size_t, N> largest_indices;
// Sort the N largest elements of array in descending order, saving their
// indices in the result variable
std::partial_sort_copy(RangeIterator{0}, RangeIterator{ArraySize},
std::begin(largest_indices), std::end(largest_indices),
compare);
return largest_indices;
}
Full code:
#include <algorithm>
#include <array>
#include <iterator>
// Range iterator type, to iterate over ranges of unsigned integers
struct RangeIterator {
using value_type = size_t;
using reference = const size_t &;
using pointer = void;
using difference_type = ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
value_type idx;
reference operator*() const { return idx; };
RangeIterator &operator++() { return ++idx, *this; }
RangeIterator operator++(int) { RangeIterator t = *this; ++idx; return t; }
bool operator!=(RangeIterator other) const { return idx != other.idx; }
bool operator==(RangeIterator other) const { return idx == other.idx; }
};
// Return the indices of the N largest elements in the array
template <size_t N, class T, size_t ArraySize>
std::array<size_t, N> max_n_elements(const std::array<T, ArraySize> &array) {
static_assert(N <= ArraySize, "Out of bounds");
// Check if the element at index a is greater than the element at index b
auto compare = [&array](size_t a, size_t b) { return array[a] > array[b]; };
// Result variable to store indices of largest elements
std::array<size_t, N> largest_indices;
// Sort the N largest elements of array in descending order, saving their
// indices in the result variable
std::partial_sort_copy(RangeIterator{0}, RangeIterator{ArraySize},
std::begin(largest_indices), std::end(largest_indices),
compare);
return largest_indices;
}
void setup() {
Serial.begin(115200);
while (!Serial);
std::array<float, 7> array = { 1.23, 2.00, 4.12, 4.00, 8.80, 6.00, 7.80 };
auto min_iter = std::min_element(std::begin(array), std::end(array));
size_t min_idx = min_iter - std::begin(array);
Serial.println("Smallest element:");
Serial.print(" ["), Serial.print(min_idx), Serial.print("]: ");
Serial.println(array[min_idx]);
auto max_3_indices = max_n_elements<3>(array);
Serial.println("Three largest elements:");
for (auto idx : max_3_indices) {
Serial.print(" ["), Serial.print(idx), Serial.print("]: ");
Serial.println(array[idx]);
}
}
void loop() {}
Output:
Smallest element:
[0]: 1.23
Three largest elements:
[4]: 8.8
[6]: 7.8
[5]: 6
Pieter