0

I have a simple script that makes a fixture matching all values of an array against all.

const players = ['a', 'b', 'c', 'd'];
const matches = [];

players.forEach(k => {
  players.forEach(j => {
    if(k !== j) {
      let z = [k, j]
      z.sort()
      const inArray = matches.indexOf(z) !== -1

      if(!inArray) matches.push(z)

      console.log(matches)
    }

  })
})

Although asking Javascript search for if z is in matches array, the result has duplicated items and returns this:

[ 'a', 'b' ]​​​​​​

​​​​​[ 'a', 'c' ]​​​​​​

​​​​​[ 'a', 'd' ]​​​​​​

​​​​​[ 'a', 'b' ]​​​​​​ --> duplicated item

​​​​​[ 'b', 'c' ]​​​​​​

​​​​​[ 'b', 'd' ]​​​​​​

​​​​​[ 'a', 'c' ]​​​​​​ --> duplicated item

​​​​​[ 'b', 'c' ]​​​​​​ --> duplicated item

​​​​​[ 'c', 'd' ]​​​​​​

​​​​​[ 'a', 'd' ]​​​​​​ --> duplicated item

​​​​​[ 'b', 'd' ]​​​​​​ --> duplicated item

​​​​​[ 'c', 'd' ]​​​​​​ --> duplicated item

How can avoid these duplicated items?

Marcelo J Forclaz
  • 718
  • 1
  • 8
  • 27
  • `indexOf()` doesn't take an array. – SLaks Jan 05 '18 at 00:42
  • 1
    `indexOf` looks for equality, so only primitives will really work like that. ie: `"a" === "a" // true`, but `[] === [] // false`. Try looking at [this question](https://stackoverflow.com/questions/237104/how-do-i-check-if-an-array-includes-an-object-in-javascript) – CRice Jan 05 '18 at 00:47
  • Why are you calling `z.sort()`? – david Jan 05 '18 at 00:54
  • They are not duplicates. It's because you are sorting them (e.g. your 2nd ['a', 'b'] is actually ['b', 'a'] – Cybernetic Jan 05 '18 at 00:55
  • How about a solution that doesn't generate these duplicates in the first place? `players.forEach((v,i,a) => { while(++i < a.length) matches.push([v, a[i]]) })` or `Array.from(new Set(players)).forEach(...)` if players itself may contain duplicates. – Thomas Jan 05 '18 at 07:40

2 Answers2

2

I'm assuming you meant if(!inArray) matches.push(z), right? Either way, indexOf will not compare the values of Arrays, but rather it is actually checking for referential equivalence, i.e. whether the Array instances themselves are equal.

In order to properly compare the values of your arrays, you'll probably want to write a helper function to use instead of indexOf. Luckily, this answer explains how to do just that.

Additionally, here is a great article on MDN which breaks down various kinds of equality comparisons.

hsrob
  • 169
  • 4
0

If the array items will always be strings, you could do something a little hacky, but will get the job done

const players = ['a', 'b', 'c', 'd'];
const matches = [];

players.forEach(k => {
  players.forEach(j => {
    if(k !== j) {
      let z = [k, j];

      z.sort()
      const inArray = matches.map(match=>match.join('')).indexOf(z.join('')) !== -1

      if(!inArray) matches.push(z)

      console.log(matches)
    }

  })
})

Basically you are turning the arrays into strings just before comparison which gives javascript a way to check to see if they are equal. Checking equality across array instances doesn't work and will return undesired results.