Best practices for "collections" - arrays, objects, or what?

Hi there!
I’m a UI developer for work, but now I’m teaching beginner coders with employee-to-employee quick classes.

What are people’s suggestions for array-like things? My heart is a bit old school, so I don’t mind regular old arrays with for() loops, but there isn’t a super easy syntax for deleting arbitrary elements. Or I could use objects (making up keys) but then iterating them is a little wonky?

I don’t see if this topic is clearly handled in Examples or Learn sections of the site, but it’s so fundamental! (In fact in my old Processing days, a similar issue came back to bite me because I was using ArrayList or something that got deprecated in later versions of Processing… and using Iterator objects was pretty clunky)

Also for the sake of my class I’m assembling a “good parts” reference page - I’ve always loved how Processing/P5 makes it so easy to try out these little baby examples all over its reference- a true strength of the platform and community - but I think now the sheer number of functions is daunting to the beginner, who might be better served with something focused on lines, rects, and ellipses responding to mouse state

Indeed there’s none. Generally when I need to iterate & remove in the same loop, I do it backwards: :bulb:

Huh. So I copied the code and put it into https://editor.p5js.org/kirkjerk/sketches/y_Nj7Z31q along with some diagnostic print(); statements. What I don’t understand at all, is it seems like the ball is already removed BEFORE mousePressed()? Like the first thing I do in mousePressed() is print the array out (I made it size 3 not 10), but by the first line of mousePressed it’s already only 2 items?
It’s making be feel rather stupid! Feels like a timing issue? Like somehow the console statement is executing after the other stuff has been done…

This overall feels like a weirdly big gap in p5.js. I feel like the community should be able to say “here’s a best practice for generating, iterating, adding to and removing from a collection of items” - either as arrays or js/s hashmap-ish use of objects with keys…

Code-Maven.com/logging-javascript-objects

Yeah, I forgot about that… so unusual that it’s like a “live” connection, for people who spent their programming lives safely using println debugging.

Anyway, I had two thoughts about paradigms to use, either with object-with-keys collections or with good old arrays:
https://editor.p5js.org/kirkjerk/sketches/_kxt_7wsg has the code live, but basically it might be

const things = {
  'a':{msg:'ok1'},
  'b':{msg:'killme'},
  'c':{msg:'ok2'},
};
const toKill = [];
for(const key in things) {
  const thing = things[key];
  if(thing.msg === 'killme') {
     toKill.push(key);
  }
}
toKill.forEach((x)=>delete(things[x]));

that of course requires making upkeys (I don’t really care about) and that temp array.

and trying to think about modern best practices for arrays…

let otherthings = [
   {msg:'ok1'},{msg:'killme'},{msg:'ok2'}
 ];
 otherthings = otherthings.filter((thing)=> (thing.msg !== 'killme') );
}

Filter is a little funky but maybe not too bad.

I know I’m at risking of mixing up old school js with new ECMAscript hotness that will have some browser issues, but still… I really have trouble reading the pop / tail thing… like it’s sneaking in a concatanation, right? kind of like a splice?

that’s still the way to go in my book.

Here is a processing example (not p5)

Here you can see the different types of for-loops.

  • Balls falls
  • Balls get removed when leaving the screen.
  • Balls are added with the mouse

For special cases like counting words in a poem, I use HashMap of course.



// ArrayList
ArrayList<Ball> balls;
boolean showData=false; 

void setup() {

  size(400, 800);
  balls = new ArrayList();

  // for-loop to fill ArrayList
  for (int i = 0; i < 10; i++) { 

    Ball newBall = makeBall(); 
    balls.add(newBall);
    //
  } // for
  //
} // func 

Ball makeBall() {

  int rectWidth = 20;
  int rectHeight = 20;
  float rCol, gCol, bCol;

  rCol = random(255);
  gCol = random(255);
  bCol = random(255);

  color newColor = color(rCol, gCol, bCol);

  return
    new Ball(random(width-rectWidth), random(height-rectHeight), 
    rectWidth, rectHeight, 
    newColor);
}

void draw() {

  background(255); // white

  if (showData) {
    // for-loop in long form 
    for (int i = 0; i < balls.size(); i++) { 
      Ball ball = balls.get(i);
      ball.displayData(i*13 + 40);
    } // for
  } else {

    // for-loop in short 
    for (Ball ball : balls) { 
      ball.display( false );
    } // for

    // for-loop backward to remove balls 
    for (int i = balls.size()-1; i>=0; i--) { 
      Ball ball = balls.get(i);
      if (!ball.isAlive) // ! means not 
        balls.remove( i );  // remove i from list
    } // for

    fill(0);  // black 
    text ("number of balls: "
      +balls.size()
      +". \nPress a key (toggle view) or mouse (add ball).", 
      14, 14);
    //
  }
  //
} // func 

void keyPressed() {
  showData= !showData;
}

void mousePressed() {
  Ball newBall = makeBall(); 
  balls.add(newBall);
}

// ==================================================

class Ball {  

  // position
  float x;
  float y;

  // size
  float w;
  float h;

  // color 
  color colBall;

  // Is it still alive?
  boolean isAlive = true; 

  // constr 
  Ball(float tempX, float tempY, 
    float tempW, float tempH, 
    color tempColBall) {

    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;  
    colBall = tempColBall;
  } // constr 

  void display( boolean withStroke ) {
    if (withStroke) {
      strokeWeight(3); 
      stroke(0);
    } else {
      noStroke();
    }
    fill(colBall);
    ellipse(x, y, w, h);

    y+=3;

    if (y > height+12) { 
      isAlive = false;
      y=0;
    }
  } // method 

  void displayData( int yTextValue ) {
    text(x+", "+y, 
      33, yTextValue);
  }
  //
} // class
//
1 Like

https://editor.p5js.org/kirkjerk/sketches/pin9ZbkXe - there’s my example, roughly equivalent to the functionality in your ball program I think, but I think the filter() is easier to understand than backwards iteration with pop and tail…

2 Likes

Thank you so much for this example on arrayList’s Chrisir.
It is super clear.

1 Like