简体   繁体   English

用Lodash比较数组的数组

[英]Comparing arrays of arrays with Lodash

I can't understand how to pull arrays from one array out of another. 我不明白如何从一个数组中取出另一个数组。

I tried using plain JavaScript (ES6): 我尝试使用普通JavaScript(ES6):

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

I expected the final openTiles to be: [[1, 3]] but it is unchanged. 我期望最终的openTiles为:[[1,3]],但它没有改变。 The problem is, the code above uses JavaScript's standard comparison (===) which can't compare one array with another. 问题是,上面的代码使用JavaScript的标准比较(===),无法将一个数组与另一个数组进行比较。 Lodash has the _.isEqual() function but I can't understand how to implement it. Lodash具有_.isEqual()函数,但我不知道如何实现它。

I tried: 我试过了:

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

but that gives me an empty array. 但这给了我一个空数组。 I would like to see how people incorporate Lodash's _.isEqual() function so that all the arrays in usedTiles can be removed from openTiles. 我想看看人们如何结合Lodash的_.isEqual()函数,以便usedTiles中的所有数组都可以从openTiles中删除。

A simple method would be to stringify the arrays you want to compare against, so that .includes will work properly: 一种简单的方法是对要比较的数组进行字符串化处理,以便.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); 

Or you can compare every value explicitly: 或者,您可以显式比较每个值:

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

For a less generic solution that just checks whether index 0 is equal to index 1: 对于不太通用的解决方案,它仅检查索引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); 

Rather than trying to write a general-purpose object- or array-equals function, or using the ones from lodash, Ramda, underscore, etc, you can write one specific to your type. 您可以编写特定于您的类型的方法,而不必尝试编写通用的对象或数组等于函数,或使用lodash,Ramda,下划线等函数。 If your tiles are just two-element arrays, then simply write an equals function that reflects that. 如果您的图块只是两个元素的数组,则只需编写一个equals函数即可反映这一点。 Then you can use it in some : 然后,您可以在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)) 

As to why your code above didn't work, there are two problems. 至于为什么上面的代码不起作用,有两个问题。 You don't want to know if every used tile matches your current one. 您不想知道是否every用磁贴都与您当前的磁贴匹配。 You only want to know is some of them do. 您只想知道some是。 Then because those are the ones you want to remove, you need to negate this for filter . 然后,由于这些是您要删除的那些,因此您需要对此进行否定以filter So you want something like !usedTiles.some(...) . 所以你想要像!usedTiles.some(...)这样的东西。

But there is another problem. 但是还有另一个问题。 You don't return anything in the callback to every / some : 您不会在回调函数中返回任何内容到every / some

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

You need to switch this to either 您需要将其切换为

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

or 要么

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

It's an easy mistake to make, and it's quite common. 这是一个容易犯的错误,而且很常见。 If you're using an arrow function with a { - } delimited block, you need a return statement. 如果您使用带有{ - }分隔块的箭头功能,则需要一个return语句。

To subtract one array from another lodash contains a series of difference methods. 从另一个lodash中减去一个数组包含一系列差分方法。

Since the value in your case is an array, simple equality won't work because [] !== [] . 由于您的情况下的值是一个数组,因此简单的相等将不起作用,因为[] !== [] Lodash's _.isEqual() performs a deep comparison between two values. Lodash的_.isEqual()在两个值之间进行了深层比较。

To combine a difference subtraction with an _.isEqual() check use _.differenceWith() . 要将差减与_.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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM