Repeating and randomizing string arrays

hello everyone!

it’s quite a simple question, but I tried to repeat values I have on an existing string array and then randomizing their positions.

using a ‘for’ method I returned out of bounds, presumably because I didn’t declared the string length properly. for that, I used expand(), which didn’t allow me for some odd reasons. (I researched a little bit and it seems the expand function doesn’t work very well for 2D arrays)

then I tried the copyArray() function, but it also returned of out bounds, since my length isn’t yet correct.

all that said and no code posted, I just wanted to gather some examples of string arrays having its values repeated and then shuffled.

thanks all for the attention!

2 Likes

hey Loop! once again you are there for the rescue, thanks a lot!

the thing is, and I might be aware that it should be a lack of knowledge issue on my part, I don’t know the specifics on using arrays, strings, lists and all of those.

/*

 enTro
 
 
 */

import controlP5.*;
import processing.video.*;

ControlP5 cp5;
Capture cam;

Textfield infosInput; // naming textfield for better calling throughout the code

int state = 0;
int MAXSTATE = 6; // numbers of questions to implement switch/case

String infos;
String infosOutput[];
String infosOutputFilled[];

void setup() {

  size (500, 500);

 // String[] cameras = Capture.list();

  cp5 = new ControlP5(this);

  cp5.addTextarea("titulo")
    .setPosition(100, 100)
    .setSize(400, 40)
    .setFont(createFont("arial", 30))
    .setLineHeight(14)
    .setColor(color(128))
    .setColorBackground(color(185, 100))
    .setColorForeground(color(255, 100))
    .setText("enTro");

  cp5.addTextarea("clique")
    .setPosition(280, 295)
    .setSize(200, 25)
    .setFont(createFont("arial", 12))
    .setLineHeight(14)
    .setColor(color(135))
    .setColorBackground(color(198, 100))
    .setColorForeground(color(255, 100))
    .setText("ENTER para continuar...")
    ;

  infosInput = cp5.addTextfield("")          //declared earlier, I name the textfield to aid later calling
    .setPosition(120, 100)
    .setSize(390, 30)
    .setFont(createFont("arial", 30))
    .setColor(color(128))
    .setColorBackground(color(185, 100))
    .setColorForeground(color(255, 100))
    ;

  cp5.addTextarea("nome")
    .setPosition(20, 350)
    .setSize(320, 40)
    .setFont(createFont("arial", 26))
    .setLineHeight(14)
    .setColor(color(120))
    .setColorBackground(color(195, 100))
    .setColorForeground(color(249, 100))
    .setText("digite seu nome");

  /* camera settings 

  if (cameras.length == 0) {
    println("There are no cameras available for capture.");
    exit();
  } else {
    println("Available cameras:");
    for (int i = 0; i < cameras.length; i++) {
      println(cameras[i]);
    }

    // The camera can be initialized directly using an 
    // element from the array returned by list():
    cam = new Capture(this, cameras[0]);
  } */
}

void draw() {

  background(0);

  // if (cam.available() == true) {
  // cam.read();
  // } 

  switch (state) {
  case 0:  //splash screen
    cp5.get(Textarea.class, "titulo").setVisible(true);
    cp5.get(Textarea.class, "clique").setVisible(false);
    cp5.get(Textarea.class, "nome").setVisible(false);
    cp5.get(Textfield.class, "").setVisible(false);
    break;

  case 1:                                                  //enter to continue
    cp5.get(Textarea.class, "titulo").setVisible(true);
    cp5.get(Textarea.class, "clique").setVisible(true);
    break;

  case 2:                                                  //user inputs their name
    // cam.start();
    cp5.get(Textarea.class, "titulo").setVisible(false);
    cp5.get(Textarea.class, "clique").setVisible(false);   //hides unused textfields
    cp5.get(Textfield.class, "").setVisible(true);
    cp5.get(Textfield.class, "").setPosition(120, 100);
    cp5.get(Textarea.class, "nome").setVisible(true);
    cp5.get(Textarea.class, "nome").setText("digite seu nome");
    cp5.get(Textarea.class, "nome").setPosition(20, 350);
    // saveFrame();
    break;

  case 3:                                                  //user inputs their age
    cp5.get(Textfield.class, "").setPosition(180, 80);
    cp5.get(Textarea.class, "nome").setText("digite sua idade"); //changes the question of the box, in order to avoid creating multiple fields
    cp5.get(Textarea.class, "nome").setPosition(30, 280);        //slightly changes the position for aesthetics
    // saveFrame();
    break;  

  case 4:                                                  //user inputs their nationality
    cp5.get(Textfield.class, "").setPosition(100, 90);
    cp5.get(Textarea.class, "nome").setText("digite sua nacionalidade"); 
    cp5.get(Textarea.class, "nome").setPosition(45, 200);
    // saveFrame();
    break;

  case 5:                                                  //user inputs their belief
    cp5.get(Textfield.class, "").setPosition(180, 140);
    cp5.get(Textarea.class, "nome").setText("descreva sua religião"); 
    cp5.get(Textarea.class, "nome").setPosition(250, 120);
    // saveFrame();
    break;

  case 6:  //user inputs their skin tone
    // cam.stop();
    cp5.get(Textfield.class, "").setPosition(230, 80);
    cp5.get(Textarea.class, "nome").setText("qual sua descrição fenotípica");
    cp5.get(Textarea.class, "nome").setSize(420, 40); 
    cp5.get(Textarea.class, "nome").setPosition(95, 30);
    break;
  }
}

void keyPressed() {
  
  for (int j=0; j<=100; j++) {
  infosOutput = infosOutput + infosOutput[j];
  infosOutputFilled = infosOutputFilled + infosOutputFilled[j];
  }

  if ( key == ENTER || key == RETURN)
  {
    /*
     
     this step is reserved for saving the string into a .txt, but it raises the question: is it better to do
     after each single keypress or at the very end of the program, when a whole string is formed?
     
     that written, need to research a method for:
     
     - saving textfield into a .txt;
     - each answer from the user is stored in the same .txt;
     - preferrably in this step I already multiply randomly the answers throughout the strings, in order to generate a treemap afterwards:
     http://www.generative-gestaltung.de/2/sketches/?01_P/P_3_1_4_01;
     
     */
    if (state > 1)
    {
      // even in state 3 we execute the following lines and save afterwards (so please no else if)
      infos = infos + "#" + infosInput.getText();
      infosInput.setText("");
      println("boink: "+infos);
    }  
    if (state == 6)
    {
      
      // saving 
      infos=infos.trim(); 
      if (infos.charAt(0) == '#') 
        infos=infos.substring(1); // delete leading # 
      // println("new:"+infos); 
      String[] infosOutput1 = split(infos, '#');
      
      //expanding string with the information
      infosOutput1 = expand(infosOutput1, 100);

      //randomizing its contents
      for (int j=0; j<100; j++)
      {
        arrayCopy(infosOutput1, j, infosOutput1, j+4, 100);
      }

      // reference says: saveStrings(filename, data)
      saveStrings(infosOutput1[0] + ".txt", infosOutput1);
      // println(infos);
    } 
    if (state==0) {
      // reset
      infos="";
    }


    state = (state+1) % (MAXSTATE+1);

    println(state);
  }
}

I think you remember this; in line 189 I try to expand and then randomize. in this particular case I’m showing, having the array filled with the already present information and then randomized, would you recommend using the hex color code, using String arrays? once again I’m not familiar with some classes, I come from a very basic C background and jumped right to Processing.

if that is the case, I’ll try to replace everything in my code with that, and if you have any readings aside from the reference I’d be thankful to have a look at!

thanks again!

Is this the line 189: String[] infosOutput1 = split(infos, '#');
Sorry, can you be more specific?

actually, those lines starting from here

//expanding string with the information
      infosOutput1 = expand(infosOutput1, 100);

      //randomizing its contents
      for (int j=0; j<100; j++)
      {
        arrayCopy(infosOutput1, j, infosOutput1, j+4, 100);
      }

I tried to use expand and then arrayCopy, and neither worked… I’m not sure this a case-specific compared to those you shown me, but since I’m storing letters and such it didn’t behave as I expected!

thanks a lot

The shuffle() function from the 1st link I’ve posted is for arrays of datatype int only:

@SafeVarargs final int[] shuffle(final int... arr) {
  if (arr == null)  return null;
 
  int idx = arr.length;
 
  while (idx > 1) { 
    final int rnd = (int) random(idx--), tmp = arr[idx];
    arr[idx] = arr[rnd];
    arr[rnd] = tmp;
  }
 
  return arr;
}

For object-typed arrays, we need to convert it, like this:

@SafeVarargs final <T> T[] shuffle(final T... arr) {
  if (arr == null)  return null;

  int idx = arr.length;

  while (idx > 1) { 
    final int rnd = (int) random(idx--);
    final T tmp = arr[idx];

    arr[idx] = arr[rnd];
    arr[rnd] = tmp;
  }

  return arr;
}

Alternatively, as the 2nd posted link advises, we can use the not-so-new Processing containers.

For strings, we use a StringList: StringList / Reference / Processing.org

So we can have access to its methods StringList::shuffle() & StringList::array():

  1. shuffle() / Reference / Processing.org
  2. array() / Reference / Processing.org
2 Likes

ohyeah!

things have been worked out!

I got some issues before shuffling since my String needed to be filled first, so I kinda brute forced it

// println("new:"+infos); 
      String[] infosOutput1 = split(infos, '#');
      String[] infosOutput2 = split(infos, '#');  //saving index

      //expanding string with the information
      infosOutput1 = expand(infosOutput1, 1000);

      for (int j = 4; j < 999; j++)
      { 
        infosOutput1[j+1] = infosOutput1[k];
        k++;

        if (k > 4) //paying attention on k value related to state/questions value!!!!!
        {
          k = 0;
        }
      }

and then used your shuffle solution!

just to clarify and not copyn’n’paste it, the syntax

final String[] shuffle(final String... arr) 

means that it’s a ‘final’ variable, String Class, using String argument later named ‘arr’, right? but what’s up with those ellipsis ‘…’? and what is the purpose of the last line inside shuffle()?

arr[rnd] = tmp;

but then again you helped me a lot! I will have some more questions later on, but I’ll create some new topics for it. cya

1 Like

Upper expression assigns a randomly chosen index [rnd] to the current index [idx].

After that, the randomly chosen index [rnd] is assigned w/ the previous index [idx] value tmp.

That is effectively a value swapping between the randomly chosen index [rnd] & the current index [idx].

For more info about this Fisher–Yates shuffling algorithm, go here: Fisher–Yates Shuffle

2 Likes