0

By comparing two arrays with same numbers, IndexOf returns false.

It also doesn´t work for single numbers e.g. position[i].location[j]. I would like to compare the whole array, not only single ints. [32, 33, 34] & [35, 34, 33] should also return true... Is there a better way?

(...)
//Array of ship locations
ships: [
        {location:[13, 23, 33]},
        {location:[2, 12, 22]},
        {location:[15, 14, 16]},
        {location:[17, 18, 19]},
        {location:[31, 41, 51]},
        {location:[40, 41, 42]}
    ],
//Array with additional ship location
position: [
        {location: [2, 12, 22]},
        {location: [40, 41, 42]}
    ],    


collision: function(position) {

     if(this.ships.length > 1) {

            for(var i = 0; i < this.ships.length; i++) {
                for(var j = 0; j < position.length; j++) {


            if(this.ships[i].location.indexOf(this.position[j].location) >= 0) {
                        return true;
                           } else {
                            return false;
                               }
                }

            }

      } else {
          return false;
      }


}

console.log(model.collision(model.position)); //returns false
  • 2
    This would provide as defined answer for your Question. https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript – Pasan Chamikara May 22 '19 at 01:01
  • 1
    Possible duplicate of [How to compare arrays in JavaScript?](https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript) – Cully May 22 '19 at 01:06
  • Yes, indeed the method includes() works really good! Even on partially equal arrays... – user3612671 May 22 '19 at 01:12

3 Answers3

1

The .indexOf method won't work on complex objects like arrays or object literals in javascript because of behavior known as "Passed by Value vs Passed by Reference". It's a lengthy subject relating to how primitive values (strings, numbers, booleans) are stored vs how complex values (objects) are stored.

If you want to compare whether two arrays are "the same" (that is, if two arrays contain the same sequence of integers), you have to check each index in each array.

1

To find a collision in your scenario you need do iterate over the first set and for each array check if any/some of the elements are present in the other set of arrays. Here is a code that does this:

let ships = [ {location:[13, 23, 33]}, {location:[2, 12, 22]}, {location:[15, 14, 16]}, {location:[17, 18, 19]}, {location:[31, 41, 51]}, {location:[40, 41, 42]} ]
let position = [{location: [22, 12, 22]},{location: [40, 41, 42]}]

// Compares if two arrays of numbers in this case are equal by making sure values 
// at array indexes are equal
let isSameArray = (a,b) => a.every((number, index) => b[index] === number)

// Compares the sets by iterating over each of the elements inside and 
// calling `isSameArray`
let contains = (a,b) => a.some(x => b.some(y => isSameArray(x.location, y.location)))

console.log(contains(ships, position)) // true
console.log(contains([{location:[22, 12, 22]}],[{location:[2, 12, 22]}])) // false

this in ES5 would look like this:

let ships = [ {location:[13, 23, 33]}, {location:[2, 12, 22]}, {location:[15, 14, 16]}, {location:[17, 18, 19]}, {location:[31, 41, 51]}, {location:[40, 41, 42]} ]
let position = [{location: [22, 12, 22]},{location: [40, 41, 42]}]

let isSameArray = function(arr1, arr2){
  return arr1.every(function(number, index){
    return arr2[index] === number
  })
}

let contains = function(setA, setB){
  return setA.some(function(objA) {
    return setB.some(function(objB) {
      return isSameArray(objA.location, objB.location)
    })
  })
}

console.log(contains(ships, position))  // true
console.log(contains([{location:[22, 12, 22]}],[{location:[2, 12, 22]}]))  // false

Now this code uses Array.some and Array.every which both return boolean in the first case indicating that all elements matched the predicate function and in the second that there was at least one match.

You can also do it with your approach as long as you include an actual function to compare the location number arrays:

let ships = [ {location:[13, 23, 33]}, {location:[2, 12, 22]}, {location:[15, 14, 16]}, {location:[17, 18, 19]}, {location:[31, 41, 51]}, {location:[40, 41, 42]} ]
let position = [{location: [22, 12, 22]},{location: [40, 41, 42]}]

let isSameArray = function(arr1, arr2){
  return arr1.every(function(number, index){
    return arr2[index] === number
  })
}

let collision = function(arr1, arr2) {
  for(var i = 0; i < arr1.length; i++) {
    for(var j = 0; j < arr2.length; j++) {
      if(isSameArray(arr1[i].location, arr2[j].location))
 return true
    }
  }
  return false
} 

console.log(collision(ships, position))   // true
Akrion
  • 18,117
  • 1
  • 34
  • 54
0

I tried .includes(); instead of .indexOf(); and it works fine. Even I don´t know why...