Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

CoffeeScript disrupts the elements in the array


May 09, 2021 CoffeeScript


Table of contents


Disrupt the elements in the array

Problem

You want to disrupt the elements in the array.

Solution

Fisher-Yates shuffle is an efficient and fair way to randomize elements in an array. T his is a fairly simple approach: start at the end of the list and swap a random element for the last element in the last element list. C ontinue to the next one and repeat until you reach the beginning of the list, and eventually all the elements in the list are disrupted. This (Fisher-Yates shuffle Visualization) (http://bost.ocks.org/mike/shuffle/) can help you understand the algorithm.

shuffle = (source) ->
  # Arrays with < 2 elements do not shuffle well. Instead make it a noop.
  return source unless source.length >= 2
  # From the end of the list to the beginning, pick element `index`.
  for index in [source.length-1..1]
    # Choose random element `randomIndex` to the front of `index` to swap with.
    randomIndex = Math.floor Math.random() * (index + 1)
    # Swap `randomIndex` with `index`, using destructured assignment
    [source[index], source[randomIndex]] = [source[randomIndex], source[index]]
  source

shuffle([1..9])
# => [ 3, 1, 5, 6, 4, 8, 2, 9, 7 ]

Discuss

In the wrong way

There is a common but wrong way to disrupt arrays: through random numbers.

shuffle = (a) -> a.sort -> 0.5 - Math.random()

If you make a random order, you should get a random sequence of sequences, right? E ven Microsoft uses this random sorting algorithm. I t turns out that this random sorting algorithm produces biased results http://blog.codinghorror.com/the-danger-of-naivete/ because it has the illusion of shuffle. Random sorting does not result in a shuffle of work, it can result in uneven sequence sorting quality.

Optimization of speed and space

The above solutions handle different speeds. T he list, when converted to JavaScript, is much more complex than it is, and transsexual allocation is much slower than working with bare variables. T he following code is not perfect and requires more source code space ... However, it compiles less and runs faster:

shuffle = (a) ->
  i = a.length
  while --i > 0
    j = ~~(Math.random() * (i + 1)) # ~~ is a common optimization for Math.floor
    t = a[j]
    a[j] = a[i]
    a[i] = t
  a

Extend Javascript to include out-of-order arrays

The following code adds the disorder function to the array prototype, which means that you can run it in any desired array and run it in a more direct way.

Array::shuffle ?= ->
  if @length > 1 then for i in [@length-1..1]
    j = Math.floor Math.random() * (i + 1)
    [@[i], @[j]] = [@[j], @[i]]
  this

[1..9].shuffle()
# => [ 3, 1, 5, 6, 4, 8, 2, 9, 7 ]

Note: Although it is fairly common in ruby languages, extending local objects in JavaScript is generally considered a bad practice (Reference: Maintainable JavaScript: Don't modify objects you don't't own).
As mentioned, the addition of the above code is very secure. I t just needs to add Array:: shuffle If it doesn't exist, add an assignment operator (?? T hat way, we don't rewrite someone else's code, or the way the local browser does it.

Also, if you think you'll use a lot of useful features, consider using a tool library like Lo-dash. T hey have many features, like simple and efficient maps across browsers. Underscore is also a good choice.