Array Variable Name Return and Highest Three (3) Variable Return?

Hi Guys,

Need some help with Arrays, the example I'm testing with I need to extract more information out of them, I can get the highest and lowest values but I'm after some additional results, these are:

  1. Return the variable name that has returned the highest and lowest value.
  2. Return the highest three (3) variable names and there associated value.
// Variable manual assignment for testing
float varvin1 = 1.23;
float varvin2 = 2.00;
float varvin3 = 4.12;
float varvin4 = 4.00;
float varvin5 = 8.80;
float varvin6 = 6.00;
float varvin7 = 7.80;

// High low variable
float lowvariable = 0.0;
float highvariable = 0.0;

void setup() {
  Serial.begin(9600);
}

void loop() {

  // Array
  float array[] = {varvin1, varvin2, varvin3, varvin4, varvin5, varvin6, varvin7};
  float count = sizeof(array) / sizeof(array[0]);
  float batvolts = count;
  float lowvariable = 100;
  float highvariable = 0;

  // Get lowest
  for (int i = 0; i < count; i++)
  {
    if (array[i] < lowvariable)
    {
      lowvariable = array[i];
    }
  }
  Serial.print("Lowest Variable: ");
  Serial.println(lowvariable);

  // Get highest
  for (int j = 0; j < count; j++)
  {
    if (array[j] > highvariable)
    {
      highvariable = array[j];
    }
  }
  Serial.print("Highest Variable: ");
  Serial.println(highvariable);
  delay (2000);

}

The variables ultimately will be sensor populated variables.

Thanks heaps!

Cheers, nic

I would start using a two dimensional array with a key and a value. And then sort the array by value.

I am not sure how easy that is in C/C++ on an Arduino. There are likely standard sort function for one dimensional arrays. Maybe you need to write your own sort function.

Variable names are gone once compiled

Use a struct to group a variable ID and its value
Create an array of these struct
Sort the array Against values In descending order
Your answer is in the first 3 elements

There are tons of sorting algorithms and given your list is small they all would go fast enough unless you have heavy time constrains.

(Eg bubbleSort is easy to grasp and just a few lines without using much temporary memory but not the most time efficient. Read about Timsort if you want to explore alternatives)

Why do you need the variable name? What's the point of that? This ain't javascript. Perhaps what you actually need is a reference or pointer? http://xyproblem.info/

PaulMurrayCbr:
Why do you need the variable name? What's the point of that?

my guess is that OP wants to know which sensors delivered the 3 highest value.

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

if you want simpler code (C style) without using any library, here is an example. A sensor is described in the t_data type and I create an array of those. Here a sensor has a name (sensorName), a value (sensorValue) which it gets from an analogRead() on a specific pin (sensorPin).

The sorting algorithm used is "Bubble Sort" which is quite short to code, sorts the array in place, and requires just a single temporary data_t structure to handle the sorting (to perform the swap). Drawback is that it's slow compared to other sorting algorithms but if you only have a handful of value to sort it's usually no big deal.

The loop is super simple, you read the sensors, you sort the array, you print the array and wait a bit before doing it again.

struct t_data {
  const char * sensorName;
  byte  sensorPin;
  float sensorValue;
};

// our array of sensors
t_data varvin[] =
{
  {"sensor 1", A0, 0.0},
  {"sensor 2", A1, 0.0},
  {"sensor 3", A2, 0.0},
  {"sensor 4", A3, 0.0},
  {"sensor 5", A4, 0.0},
  {"sensor 6", A5, 0.0},
};

// the number of sensors
const size_t nbSensors = sizeof varvin / sizeof varvin[0];

// --- BUBBLE SORT ---
void swap(t_data * a, t_data * b)
{
  t_data temp = *a; // shallow copy (structure assignment)
  *a = *b;
  *b = temp;
}

// A function to implement bubble sort
void bubbleSort(t_data arr[], size_t count)
{
  for (size_t i = 0; i < count - 1; i++)
    for (size_t j = 0; j < count - i - 1; j++)
      if (arr[j].sensorValue < arr[j + 1].sensorValue) // use > if you want to sort ascending order
        swap(&(arr[j]), &(arr[j + 1]));
}

// ------ UPDATE ALL THE SENSORS -----
void readSensors()
{
  for (size_t i = 0; i < nbSensors; i++)
    varvin[i].sensorValue = analogRead(varvin[i].sensorPin); // whatever you need to do to read your sensor #I
}

// ------ PRINT ALL THE SENSORS -----
void printSensors()
{
  for (size_t i = 0; i < nbSensors; i++) {
    Serial.print(varvin[i].sensorName);
    Serial.print(F(" -> "));
    Serial.println(varvin[i].sensorValue);
  }
  Serial.println(F("-----------------------"));
}

// ------ THE CODE -----
void setup() {
  Serial.begin(115200);
}

void loop()
{
  readSensors();
  bubbleSort(varvin, nbSensors);
  printSensors();
  delay(1000);
}

of course have your Serial monitor opened at 115200 bauds and you'll see that the array is always printed in descending order, with the name of each sensor.

Serial Monitor (@ 115200 bauds) will show

[color=purple]
sensor 1 -> 412.00
sensor 2 -> 398.00
sensor 6 -> 393.00
sensor 3 -> 389.00
sensor 4 -> 389.00
sensor 5 -> 383.00
-----------------------
sensor 1 -> 324.00
sensor 6 -> 318.00
sensor 2 -> 311.00
sensor 3 -> 303.00
sensor 4 -> 300.00
sensor 5 -> 293.00
-----------------------
sensor 6 -> 326.00
sensor 4 -> 320.00
sensor 2 -> 318.00
sensor 3 -> 316.00
sensor 1 -> 311.00
sensor 5 -> 311.00
-----------------------
sensor 1 -> 362.00
sensor 2 -> 361.00
sensor 4 -> 359.00
sensor 3 -> 359.00
sensor 6 -> 356.00
sensor 5 -> 338.00
-----------------------
...
[/color]

awesome thanks guys for the options and example scripts, really appreciate it! Need to get the variable name so I know which solid state relay to turn on which then turns on current flow for a ground isolated circuit