使用Lodash比较数组的数组

问题描述 投票:0回答:3

我无法理解如何从一个阵列中拉出数组。

我尝试使用纯JavaScript(ES6):

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]
openTiles = openTiles.filter((item) => !usedTiles.includes(item))

我预计最终的openTiles是:[[1,3]]但它没有变化。问题是,上面的代码使用JavaScript的标准比较(===),它无法将一个数组与另一个数组进行比较。 Lodash有_.isEqual()函数,但我无法理解如何实现它。

我试过了:

openTiles = openTiles.filter((item) => {
    return usedTiles.every((el) => {
        _.isEqual(item, el)
    })
})

但这给了我一个空数组。我想看看人们如何合并Lodash的_.isEqual()函数,以便可以从openTiles中删除usedTiles中的所有数组。

javascript ecmascript-6 lodash
3个回答
3
投票

而不是尝试编写通用对象或数组等于函数,或使用来自lodash,Ramda,下划线等的函数,您可以编写一个特定于您的类型的函数。如果你的tile只是两个元素的数组,那么只需编写一个反映它的equals函数。然后你可以在some中使用它:

const tilesEqual = (a) => (b) => a[0] == b[0] && a[1] == b[1]
const removeTiles = (open, used) => open.filter(
  tile => !used.some(tilesEqual(tile))
)

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]

console.log(removeTiles(openTiles, usedTiles))

至于为什么上面的代码不起作用,有两个问题。您不想知道every使用的瓷砖是否与您当前的瓷砖匹配。你只想知道他们做的some。那么因为那些是你要删除的,你需要为filter否定这个。所以你想要像!usedTiles.some(...)这样的东西。

但还有另一个问题。你不会在回调中向every / some返回任何内容:

    return usedTiles.every((el) => {
        _.isEqual(item, el)
    })

您需要将其切换为其中之一

    return usedTiles.every((el) => _.isEqual(item, el))

要么

    return usedTiles.every((el) => {
        return _.isEqual(item, el)
    })

这是一个容易犯的错误,而且很常见。如果你使用带有{-}分隔块的箭头函数,你需要一个return语句。


3
投票

一个简单的方法是对要比较的数组进行字符串化,以便.includes正常工作:

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]
const usedTilesStringified = usedTiles.map(JSON.stringify);
openTiles = openTiles.filter((item) => !usedTilesStringified.includes(JSON.stringify(item)))
console.log(openTiles);

或者您可以明确地比较每个值:

let openTiles = [[1, 1], [2, 2], [1, 3]];
let usedTiles = [[1, 1], [2, 2]];
openTiles = openTiles.filter((item) => {
  const { length } = usedTiles;
  outer:
  for (let i = 0, { length } = usedTiles; i < length; i++) {
    const usedTile = usedTiles[i];
    if (usedTile.length !== item.length) {
      continue;
    }
    for (let j = 0, { length } = usedTile; j < length; j++) {
      if (usedTile[j] !== item[j]) {
        // The current subarrays being compared are not identical:
        continue outer;
      }
    }
    // We've iterated through all indicies while comparing one subarray to another
    // they all match, so the arrays are the same, so this filter fails:
    return false;
  }
  return true;
})
console.log(openTiles);

对于不太通用的解决方案,只检查索引0是否等于索引1:

let openTiles = [[1, 1], [2, 2], [1, 3]];
let usedTiles = [[1, 1], [2, 2]];
openTiles = openTiles.filter((item) => {
  for (let i = 0, { length } = usedTiles; i < length; i++) {
    const usedTile = usedTiles[i];
    if (usedTile[0] === item[0] && usedTile[1] === item[1]) {
      return false;
    }
  }
  return true;
})
console.log(openTiles);

1
投票

从另一个lodash中减去一个数组包含一系列差异方法。

由于您的案例中的值是一个数组,因此简单的相等不起作用,因为[] !== []。 Lodash的_.isEqual()对两个值进行了深入的比较。

要将差异减法与_.isEqual()结合使用,请使用_.differenceWith()

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]
openTiles = _.differenceWith(openTiles, usedTiles, _.isEqual)

console.log(openTiles)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
© www.soinside.com 2019 - 2024. All rights reserved.