DEV Community

loading...
Cover image for Why I don't like JavaScript

Why I don't like JavaScript

sk9 profile image sk9 ・1 min read

When I want to get a unique random sequence ...

R

print(sample(1:10, 10))

happy

Python

import random
l = list(range(1, 10 + 1))
print(random.sample(l, 10))

happy

JavaScript

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function getRandomArray(min, max) {
  let result = [];
  for (i = min; i <= max; i++) {
    while (true) {
      let v = getRandomInt(min, max);
      if (!result.includes(v)) {
        result.push(v);
        break;
      }
    }
  }
  return result;
}

console.log(getRandomArray(1, 10));

angry

Discussion (8)

pic
Editor guide
Collapse
stephenramthun profile image
Stephen Ramthun • Edited

While I get that this is a joke, that getRandomArray-function is a bit verbose. This does the same thing:

new Array(10).fill(0).map(() => getRandomInt(1, 10))

Edit: unique list:

new Array(10).fill(1).map((n, i) => n + i).sort(() => Math.random() - 0.5)
Collapse
avalander profile image
Avalander

Not really, since the intent of the original implementation is to generate a sequence of unique elements, and your implementation can yield duplicated values.

A better approach would be to just generate the sequence in order and shuffle it:

const range = (from, to) => {
  const data = []
  for (let i = from; i <= to; i++) data.push(i)
  return data
}

const randSeq = (min, max) => {
  const data = range(min, max)
  data.sort(() => Math.random() - 0.5)
  return data
}

The data.sort trick doesn't produce a lot of variations, though. A better way is to generate the sorted array and pick elements from a random index and add them to a new array.

const randSeq2 = (min, max) => {
  const data = range(min, max)
  const result = []
  while (data.length > 0) {
    const i = randInt(0, data.length - 1)
    result.push(data[i])
    data.splice(i, 1)
  }
  return result
}

At this point the implementation is equally verbose to the original, so ¯\_(ツ)_/¯. But it avoids unnecessary iterations when duplicated values are generated.

Collapse
stephenramthun profile image
Stephen Ramthun

Nice catch, thanks! Didn't realise that the list had to be unique. Could you explain what you mean by .sort() not producing a lot of variations?

Thread Thread
avalander profile image
Avalander • Edited

[].sort(() => Math.random() - 0.5) tends to not displace elements in the array a lot. An element might be moved a few positions forward or backward, but it will generally stay close to its original position. Therefore, when used to shuffle an array, the result will be more similar to the original array than with other algorithms.

As an example, here's the output of three runs with randSeq and three runs with randSeq2:

# randSeq
[ 1, 3, 4, 5, 9, 7, 6, 8, 2, 10 ]
[ 7, 1, 2, 3, 6, 8, 4, 5, 9, 10 ]
[ 2, 3, 1, 4, 6, 9, 8, 5, 7, 10 ]

# randSeq2
[ 5, 1, 7, 10, 4, 6, 3, 9, 8, 2 ]
[ 7, 1, 6, 9, 5, 8, 3, 4, 10, 2 ]
[ 2, 6, 4, 10, 9, 8, 5, 3, 1, 7 ]

You can notice that with the randSeq the array is less shuffled than with randSeq2 and the elements show a clear tendency to be larger the further back they are in the array.

Thread Thread
stephenramthun profile image
Stephen Ramthun

Makes sense. Thanks!

Collapse
ayrbox profile image
ayrbox

That's a weird reason for liking and not liking a language. 🤦‍♂️😂

Collapse
mpjdem profile image
Maarten Demeyer

That R implementation is too verbose as well, just sample(10) will do! 😛

Collapse
fly profile image
joon • Edited

Import lodash and use their sample...

It gets pretty much as short as the python version