Choose random element from array and delete afterwards

Let's say I have an array like this:

int x[ 5 ] = { "a", "b", "c", "d", "e"}

When my button is pressed, it should choose a random element set a value to be that element. But this is not the point.

What I need help with is: how do I make it so, when an action happens, it selects a random element from that array, sets it as a value, waits a few seconds, sets that value back to 0 and deletes that element from the list. I know perfectly well how this is done in JavaScript, but I'm new to this so please help.

Concept (i am aware that the void loop() is not going to work but it's put as an example:

int x[ 5 ] = { "a", "b", "c", "d", "e"}
int chosenElement = 0;

void loop() {
   random(x) = chosenElement   //choose the random element and set the value as it   
   Serial.print(chosenElement);
   wait(1);
   //something to delete the previously chosen element from the array
   chosenElement = 0;
   Serial.print(chosenElement);
}

I just need it to be as simple as possible; choose random element from array, set value and print, remove randomised element from array.
I've seen another Topic about Arrays but they're all about choosing random numbers from a consecutive list.

you define an array of int and initialise it with text strings??
try

int x[ 5 ] = {1,2,3,4,5}

initially try writing a program which generates a random number between 0 and 4 (C/C++ array index goes from 0 to SIZE-1)
then print that array element

when you specify remove that element - do you mean move the following elements down the array and set the end element to 0?
the array size is fixed unless you move to dynamic arrays

You made a global array with 5 elements.
It will have 5 elements.
You can't change that.

You could introduce a second array with 5 elements and mark elements which were already used.

But mostly I suspect a XY problem. What is your goal you want to achieve? Describe the wanted result - not the problem you have to get there.

this

Sorry, I found that in another Topic where the array had numbers. I understood how it's done like that but I need it to have words instead, if that can't be made please help me out with an array working like that but with numbers and I'll make it so each number represents a word afterwards.

By removing the element I mean that when the code runs another time the element won't be shown again. I'll search up dynamic arrays and see if they fit. Ty!

if you use fixed array lengths you need to record the number of elements used
when you remove an element

  1. move following elements down array insert 0 at end
  2. decrement number of elements

note if you are using low power microcontrollers such as the UNO avoid using dynamic arrays and similar techniques (e.g. String class) - you can fragment the memory and crash the program

1 Like

you can have array of char*, e.g.

void setup() {
  Serial.begin(115200);
  char* x[ 5 ] = { "hello", "b", "c", "d", "bye"};
  for(int i=0;i<5;i++)
     Serial.println(x[i]);
}

void loop() {}

when run the serial monitor displays

10:48:33.164 -> hello
10:48:33.164 -> b
10:48:33.164 -> c
10:48:33.164 -> d
10:48:33.164 -> bye

on more powerfull micros, e.g.Arduino Due, ESP32, etc you could have array of String class objects

void setup() {
  Serial.begin(115200);
  String x[ 5 ] = { "hello", "b", "c", "d", "bye"};
  for(int i=0;i<5;i++)
     Serial.println(x[i]);
}

void loop() {}

You could sample from a sub-array that gets progressively smaller:

int arr[] {10, 11, 12, 13, 14, 15};

for (size_t n {0}; n < 6; n++) {
  size_t i {random(n, 6)};
  Serial.println(arr[i]);
  arr[i] = arr[n];
}  

The assignment makes sure that non-selected elements will be part of the next sub-array.

Output:

11
15
13
10
14
12

As others said before, that's not really clear. C fixed size arrays can't resized, so you just need to define a "null value" and/or keep record of the current valid values, shifting the rightmost (i.e. larger index) when "removing" an item.
Assuming you have a C strings array, and as a "null value" use an empty string (i.e. the first byte is '\0'), you can just keep the "deleted" value to zero, and skipping it when using the array.
This will mantain the original index numbers, but when parsing the array you need to do something like this to get the "real" index (please note I wrote it without testing...):

char x[5][20] = { "v1", "v2", "v3", "v4", "last" };

bool delElem(int n) {
  int i = getElem(n);
  if (i == -1) return false;
  x[i][0] = '\0';
  return true;
}
int getElem(int n) {
  int cnt = -1;
  for (int i=0; i<=4; ++i) {
    if (x[i][0] != '\0') {
      if (n == ++cnt) return i;
    } 
  }
  return -1;
}
void dumpElem() {
  for (int i=0; i<=4; ++i) {
    Serial.print(i); Serial.print("=");
    Serial.println(getElem(i));
  }
}  

Or, better, this if you want to keep it "compact":

char x[5][20] = { "v1", "v2", "v3", "v4", "last" };
int topx = 4; // Index for the topmost valid item
...

bool delElem(int n) {
  if (n >=topx || topx <  0) return false;
  // now shift left all rightmost elements to fill the gap
  for (int i=n; i < topx; ++i)
    strcpy(x[i],x[i+1]);
  --topx;
  return true;
}

void dumpElem() {
  for (int i=0; i<=topx; ++i) {
    Serial.print(i); Serial.print("=");
    Serial.println(x[i]);
  }
}

Do you realize when that is done, the array is COPIED to a completely new array?

Or just take the last vakue and put it where the deleted element comes from

bool delElem(int n) {
  if (n >=topx || topx <  0) return false;

  topx--;

  if (n != topx)
    strcpy(x[n], x[topx]);

  return true;
}

if preserving the order of the original elements is unimportant.

a7

This is what was suggested in post #9.

Also, if the array is defined as a char const* arr[], no copying is needed.

char const* arr[] {"10", "11", "12", "13", "14", "15"};

for (size_t n {0}; n < 6; n++) {
  size_t i {random(n, 6)};
  Serial.println(arr[i]);
  arr[i] = arr[n];
}  

Instead of the simple assignment, swapping the elements could also be considered.

for (size_t n {0}; n < 6; n++) {
  size_t i {random(n, 6)};
  Serial.println(arr[i]);

  char const* tmp {arr[i]};
  arr[i] = arr[n];
  arr[n] = tmp;
}
// `arr` is now permutated. Ready for an other round.

[edit]

This could be put in a function for convenience, e.g.,

template <size_t n> char const* pick(char const* (& arr)[n]) {
  static size_t size {n};

  size_t i {random(size)};
  char const* tmp {arr[i]};
  arr[i] = arr[--size];
  arr[size] = tmp;

  if (not size) {
    size = n;
  }
  return tmp;
}

Usage:

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

  char const* arr[] {"10", "11", "12", "13", "14", "15"};

  // Pick six strings from the array.
  // Prints numbers 11, 14, 15, 12, 10 and 13.
  for (size_t n {0}; n < 6; n++) {
    Serial.println(pick(arr));
  }

  // Rinse and repeat.
  // Prints numbers 13, 15, 14, 10, 11 and 12.
  for (size_t n {0}; n < 6; n++) {
    Serial.println(pick(arr));
  }
}

void loop() {}

I don't have the code handy but I can describe how I do it...

I make a variable for the array size (which is decremented each time an element is used, to represent the usable array size).

After grabbing a random array element, everything to the right of that element is shifted-left, overwriting the used-element, leaving extra-duplicated elements, which won't ever be selected after decrementing the (useable) array size.

For example, if I have array 1,2,3,4,5,6,7,8,9 and I randomly select and remove the 5...

After shifting and overwriting I have 1,2,3,4,6,7,8,9,9.

Isn't the same I have shown on post #10 (including the code)? :wink:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.