Click to reset the points

CC Attribution ShareAlike

Finding the Maximum

Demonstrates finding the maximum of a set of values, arrow functions, Array map, and higher-order programming
Click to reset the points
e.g., mouse, keyboard
e.g., visualization, fractal, mouse
Learn more about Creative Commons
Join Plus+ to change privacy settings
  • This sketch creates a set of random locations, and draws circles there.

    Click to reset the set of points.

    We would like to figure out the maximum x value (next step). There are many reasons to do this. One is to in order to figure out the range of a set of values, so that we can map the range of data into a range of x or y positions that fits onto the canvas, or onto a set of sizes that is neither too big nor too small.

  • To find this, we define a function findMaxX, that finds the largest x value in a set of objects that have properties named "x".

    It uses result to keep track of the largest x value that it's seen so far. When a new x value is larger than this, it updates result.

    The first time through the loop, result does not have a value. (Well, it has the value undefined, which is not a numeric value.) The code therefore can't compare the new value to result. Instead, it treats this condition specially: the first time through the loop, it always updates result.

    This works, but the function is complicated, and it is not very reusable. (It only works on x's, and it can't find minima.) The rest of the steps will explore alternative ways to write this.

  • We can eliminate the firstTime variable by using the other form of the for loop, that steps through the index positions of the array elements instead of the elements themselves.

    This adds an extra step (on line 25) to get the array element. In return, the code inside the loop body can use this index to tell whether it is visiting the first element.

  • An alternative approach is to set the initial value of result to a sentinel value. This is a value that never shows up in the data, that we can test to see whether the variable has been initialized from the data.

    We can do better. If we pick the right sentinel value, we can eliminate lines 25–26.

    (This step changes the behavior of findMaxX when points is the empty array. Each of the remaining steps also changes its behavior for this special case. Part of the design of a function is the specification of what it should do in this kind of corner case.)

  • -10000000 is (hypothetically) smaller than any possible x value. The first time through the loop, point.x will always be greater than this negative value, and line 26 will always execute. The remaining times through the loop, line 25 comnpares x to the greatest value that it has seen in the previously-visited array elements.

    This works if our hypothesis is true (if no number < -10000000 is present in the data).

  • Here's a safer way to do the same thing. Number.MIN_VALUE is the smallest representable value in JavaScript. It is guaranteed that that point.x can never be smaller than this value.

    There's an shorter way to write lines 25–27…

  • This code is simpler (in several technical senses) than the starting code. Eliminating the extra variables and if statements makes it easier to reason about.

    The code is complex in another sense. Lines 24-26 are doing two things at once: (1) they are extracting the x values from an array of objects, and (2) they are finding the largest of this extracted set of values.

    The next step makes the code more complex in one sense (it adds another for loop), by making it simpler in the other sense (each part of the code does only one thing). This sets the code up to rewrite in other ways.

  • Lines 23–26 create a new array that contains only the x values from the input array.

    Technically, this is a "projection". Think about shining a light onto the circles from the top of the canvas so that all you see are their shadows, on the line that is the bottom of the window. We have lost the y property (and any other properties that might be present in a more sophisticated program), and extracted, or projected, only the value of the x property.

  • The previous steps use form of the p5.js max function that takes two arguments. There is another form that takes a list of values, and returns the maximum value from that list. That is exactly what lines 28–32 of findMaxX do. We can replace those lines by a single function.

    Lines 23–26 make a new array (xs) that is based on an input array (points).

    The next step separates this into two parts:

    • The code that creates and fills the new array. That will remain at the beginning of findMaxX.
    • The code that reads an element of the input array and figures out, based on this, what value to add to the new array. This is currently just the expression point.x. We will extract this computation to a function that does this same computation.
  • Line 25 of this step have the same effect as line 25 of the previous sketch.

    The advantage of writing it this way is that lines 23–26 now do exactly the same thing as the JavaScript Array.map method. (This method is unrelated to the p5.js map function.) Array.map "returns a new array containing the results of calling a function on every element in this array."

  • Here's the same code written to use Array.map.

  • projectX is only used once, as an argument to points.map. Instead of defining it (which creates a global variable named projectX), we can simply write it in the place where its value is used.

    This is just the same as, instead of defining a variable say `let five = 5` and then using `five`, we can just use the number 5.

  • When function is used as an expression, the name isn't used*. We can eliminate it.

    *The name is useful for documentation, and can appear in stack traces and in the debugger. It doesn't make any difference to the behavior of the program.

  • Here's another way to write a function, using "arrow" notation.

  • We can simplify the arrow function in two ways:

    1. When an arrow function has only a single parameter ("point:), the parentheses around the parameter list are optional. (This is true only for arrow functions, not for functions that are written using the "function" keyword.)
    2. An arrow function whose body (inside {}) is a single return statement, can be replaced by the expression after the "return", without {}.

    In this case, all of the following are equivalent function expressions:


  • findMaxX is now so simple that it's maybe not worth having as a separate function. Let's move its code back into draw…

  • How would you modify this to compute xMin? yMax and yMin?

    Can you use these to draw the bounding box – the smallest rectangle that contains all the circle centers?

    Can you use p5.js map (not Array.map) to stretch out the circle centers so that the leftmost circle is centered on the left edge of the canvas, the rightmost circle is centered on the right edge of the canvas, and the ratio of spaces between circles is maintained?

1/17
  • mySketch
Select mode or a template
Centers sketch and matches the background color.
Prevents infinite loops that may freeze the sketch.
This will be the default layout for your sketches
Easy on the eyes
It will show up when there is an error or print() in code
Potential warnings will be displayed as you type
Closes parenthesis-like characters automatically as you type

Controls
Play
Ctrl+Enter
Code
Ctrl+Shift+Enter
Save
Ctrl+S
Interface
Fullscreen
Ctrl+Alt+F
Switch Layout
Ctrl+Alt+L
Settings
Ctrl+Alt+.
Editor
Tidy Code
Ctrl+B
Multiple Cursors
Ctrl+Click
Duplicate Line/Selection
Ctrl+Shift+D
Move Line
Alt+↑/↓
Select Multiple
Ctrl+D
Find in Code
Ctrl+F
Find Next
Ctrl+G
Find Previous
Ctrl+Shift+G

See More Shortcuts

Join Plus+ for private sketches, version history, 1GB space, custom embeds, and more!