Quiero una función ( collisions ) que pueda eliminar objetos de una matriz cuando son demasiado similares. Tengo una versión funcional, pero es tan fea que no quiero cometerla.
En mi piscina de 10x10 tengo muchos barcos:
var boats = [ {name: "A", position: [1,1] }, // collides with E and G {name: "B", position: [7,8] }, // collides with D {name: "C", position: [8,2] }, // will not collide {name: "D", position: [7,9] }, // collides with B {name: "E", position: [2,1] }, // collides with A and G {name: "F", position: [1,7] }, // will not collide {name: "G", position: [2,2] }, // collides with A and E ]Los barcos deben tener cuidado de no acercarse a otros barcos.
const collisionDistance = 5; function distance(boat1, boat2) { return Math.sqrt( Math.pow(boat1.position[0] - boat2.position[0], 2) + Math.pow(boat1.position[1] - boat2.position[1], 2) ); }Si no lo hacen, ambos barcos se hundirán. (esta es la parte que necesita refactorización)
// Boats that are too close to another boat are removed from the list of boats // How can I make this beautiful? function collisions() { var collidingBoatIndices = new Set(); // iterate over pairs of the list for (let i = 0; i < boats.length; i++) { for (let j = i+1; j < boats.length; j++) { if (distance(boats[i], boats[j]) < collisionDistance) { collidingBoatIndices.add(i); collidingBoatIndices.add(j); } } } // delete from biggest to smallest index so there is no shift in the elements for (let index of Array.from(collidingBoatIndices).sort().reverse()){ console.log("Boat sank: ", boats[index]) boats.splice(index, 1); } } En la configuración anterior, espero que solo sobrevivan los barcos C y F
console.log("Boats at start:", boats.map((boat => boat.name))); collisions() console.log("Boats left over:", boats.map((boat => boat.name))); Entonces mi pregunta es: ¿Cómo puedo hacer que las collisions de funciones sean más simples y legibles?
No entiendo por qué estás guardando los índices en lugar de los barcos... mira esto:
var boats = [ {name: "A", position: [1,1] }, // collides with E and G {name: "B", position: [7,8] }, // collides with D {name: "C", position: [8,2] }, // will not collide {name: "D", position: [7,9] }, // collides with B {name: "E", position: [2,1] }, // collides with A and G {name: "F", position: [1,7] }, // will not collide {name: "G", position: [2,2] }, // collides with A and E ] const collisionDistance = 5; function distance(boat1, boat2) { return Math.sqrt( Math.pow(boat1.position[0] - boat2.position[0], 2) + Math.pow(boat1.position[1] - boat2.position[1], 2) ); } const res = [] for(let i = 0; i < boats.length ; i++){ let flag = true; for(let j = 0; j < boats.length; j++){ if(distance(boats[i], boats[j]) < collisionDistance && i != j){ flag = false; } } if(flag){ res.push(boats[i]) } } console.log( res )Pero puede tomar una forma funcional mucho más legible como esta:
var boats = [ {name: "A", position: [1,1] }, // collides with E and G {name: "B", position: [7,8] }, // collides with D {name: "C", position: [8,2] }, // will not collide {name: "D", position: [7,9] }, // collides with B {name: "E", position: [2,1] }, // collides with A and G {name: "F", position: [1,7] }, // will not collide {name: "G", position: [2,2] }, // collides with A and E ] const collisionDistance = 5; function distance(boat1, boat2) { return Math.sqrt( Math.pow(boat1.position[0] - boat2.position[0], 2) + Math.pow(boat1.position[1] - boat2.position[1], 2) ); } const res = boats.filter( (b1, i) => boats.every( (b2, j) => !(distance(b1, b2) < collisionDistance && i != j) ) ) console.log(res) Como señaló @pilchard , puede aumentar el rendimiento usando some (aunque en una hoja de 10x10 no verá tal mejora):
var boats = [ {name: "A", position: [1,1] }, // collides with E and G {name: "B", position: [7,8] }, // collides with D {name: "C", position: [8,2] }, // will not collide {name: "D", position: [7,9] }, // collides with B {name: "E", position: [2,1] }, // collides with A and G {name: "F", position: [1,7] }, // will not collide {name: "G", position: [2,2] }, // collides with A and E ] const collisionDistance = 5; function distance(boat1, boat2) { return Math.sqrt( Math.pow(boat1.position[0] - boat2.position[0], 2) + Math.pow(boat1.position[1] - boat2.position[1], 2) ); } const res = boats.filter( (b1, i) => !boats.some( (b2, j) => distance(b1, b2) < collisionDistance && i != j ) ) console.log(res)