成对地从数组中删除元素

Pairwise remove elements from array

我想要一个函数 (collisions),当它们太相似时可以从数组中删除对象。 我有一个可以工作的版本,但是太丑了,我不想提交。

设置

在我的 10x10 池中,我有很多船:

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)
  );
}

如果他们不这样做,两艘船都会沉没。 (这是需要重构的部分)

// 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);
  }
}

在上面的设置中,我希望只有 CF 的船能够存活。

console.log("Boats at start:", boats.map((boat => boat.name)));
collisions()
console.log("Boats left over:", boats.map((boat => boat.name)));

问题

所以我的问题是:如何使函数 collisions 更简单且更具可读性?

我不明白你为什么要保存索引而不是船...检查一下:

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
)

但是你可以采用这样一种更具可读性的函数式方式:

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)

最终版本

正如 @pilchard 指出的那样,您可以使用 some 提高性能(即使在 10x10 sheet 中您不会看到这样的改进):

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)