1

This is a simplified example, but say I want to generate 5 unique positions on a 100x100 grid. These positions will be stored in an array [[x, y], ...].

The tried the obvious method of generating a random x and y and checking to see if the array [x, y] is already in the result array. If it is, generate different values, if not add it to the result array.

result = [];
while (result.length !== 5) {
    let x = Math.floor(Math.random() * 100) + 1;
    let y = Math.floor(Math.random() * 100) + 1;
    if (!result.includes([x, y])) {
        result.push(array);
    }
}

However, this will never find the duplicates, as the arrays are technically different objects. So, what is the preferred method for detecting if an array contains an 'equal' array/object?

Chris
  • 358
  • 1
  • 14
  • Are you opposed to using a lodash function for this? https://stackoverflow.com/questions/29951293/using-lodash-to-compare-arrays-items-existence-without-order it may make this much easier than writing a comparison loop – Sterling Archer Apr 02 '19 at 19:40
  • 1
    `[x,y] !== [x,y]` even though values are identical – charlietfl Apr 02 '19 at 19:40

2 Answers2

3

You can use some() instead of includes() and use join() before compare

while (result.length !== 5) {
    let x = Math.floor(Math.random() * 10) + 1;
    let y = Math.floor(Math.random() * 10) + 1;
    if (!result.some(i => i.join() === [x, y].join())) {
        result.push(array);
    }
}

You can't compare two arrays by simple equality in js. For example []===[] is false. Because both arrays have difference references

console.log([] === []); //false

Same is the case with includes()

let pts = [[1,2],[5,6]];

console.log(pts.includes([1,2])); //false

console.log(pts.some(x => [1,2].join() === x.join())); //true
Chris
  • 358
  • 1
  • 14
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
  • 2
    This works here since all the values are single digits, but it might be better to use a separator for the join, which would allow it to distinguish between pairs like `[11, 2]` and `[1, 12]` if the matrix could be bigger. – Mark Apr 02 '19 at 19:45
  • Should have stated in the post, I need this to work with multiple digit numbers. Will edit the post. – Chris Apr 02 '19 at 19:48
  • You can just ignore the separator parameter like this: `.join()`. This will add a `,` by default – adiga Apr 02 '19 at 19:49
  • @adiga Thanks for information. I actually forgot about that. – Maheer Ali Apr 02 '19 at 19:51
  • `.toString()` works as well – adiga Apr 02 '19 at 19:51
1

You can use Array.some() in conjunction with destructuring:

Example:

let arr = [[1,2],[3,4]];

console.log(arr.some(([x, y]) => x === 3 && y === 4));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

So, your example, can be reworked to this:

let result = [];

while (result.length !== 5)
{
    let x = Math.floor(Math.random() * 10) + 1;
    let y = Math.floor(Math.random() * 10) + 1;

    if (!result.some(([a, b]) => a === x && b === y))
    {
        result.push([x, y]);
    }
    else
    {
        console.log(`${[x,y]} is already on the array!`);
    }
}

console.log(JSON.stringify(result));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Shidersz
  • 16,846
  • 2
  • 23
  • 48