使用lodash比较数组(项目存在而无顺序)


124

我知道我可以使用循环来做到这一点,但是我试图找到一种优雅的方式来做到这一点:

我有两个数组:

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

我想用来lodash确认以上两个数组是相同的。通过“相同的”我的意思是,有没有在项目array1中没有包含在array2

在检查这些项目之间的相等性方面:

['a', 'b'] == ['b', 'a'] 

要么

['a', 'b'] == ['a', 'b'] 

两者都可以工作,因为字母始终是有序的。

Answers:


224

如果对外部数组进行排序,则可以使用,_.isEqual()因为内部数组已被排序。

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];
_.isEqual(array1.sort(), array2.sort()); //true

请注意,这.sort()将使数组变异。如果您遇到问题,请首先使用(例如).slice()或散布运算符(...)进行复制。

或者,按照Daniel Budick在以下评论中建议的方式进行操作:

_.isEqual(_.sortBy(array1), _.sortBy(array2))

Lodash sortBy()不会改变数组。


6
考虑到array.sort()正在变异原始数组。也许这可能更好:var array1 = [['a','b'],['b','c']]; var array2 = [['b','c'],['a','b']]; _.isEqual([... array1] .sort(),[... array2] .sort()); // true
Yaniv Efraim

3
增加了两句话,指出 .sort()并建议用户优先复制的选项(如果这对用户而言是个问题)。
Trott

6
如果您已经在使用lodash,则_.isEqual(_.sortBy(array1), _sortBy(array2))可以防止突变。
Daniel Budick

1
@DanielBudick谢谢!我已将其添加到答案中。很棒的建议。
Trott

31

您可以xor为此使用破折号

doArraysContainSameElements = _.xor(arr1, arr2).length === 0

如果您认为数组[1,1]与数组[1]不同,则可以像下面这样改善性能:

doArraysContainSameElements = arr1.length === arr2.length === 0 && _.xor(arr1, arr2).length === 0

1
无论如何,都需要对数组进行排序。
Sovattha Sok,

1
对于新版本,这应该是更好的方法
莱昂纳多(Leonardo)

@Sovattha Sok不需要对数组进行排序。这样做_.xor([3,4], [4,3]).length == 0会使您成真。
Nikolay

1
请注意:此技术对于“小型”数组效果很好,但是如果您的数组很大且大多数情况下不同,则此方法可能会很痛苦,而且在内存方面会很麻烦,因为_.xor()会一直超出第一个差异。换句话说,它不会在检测到的第一个差异上快速返回。
XDS

6

“相同”是指array1中没有未包含在array2中的项目。

您可以为此使用flatten()和Difference(),如果您不在乎是否存在不在其中的项目,则array2它们会很好地工作array1。听起来您在问array1是array2的子集吗?

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

function isSubset(source, target) {
    return !_.difference(_.flatten(source), _.flatten(target)).length;
}

isSubset(array1, array2); // → true
array1.push('d');
isSubset(array1, array2); // → false
isSubset(array2, array1); // → true

4

此处已经有答案,但这是我的纯JS实现。我不确定它是否是最佳选择,但它肯定是透明的,可读的和简单的。

// Does array a contain elements of array b?
const contains = (a, b) => new Set([...a, ...b]).size === a.length
const isEqualSet = (a, b) => contains(a, b) && contains(b, a)

其基本原理contains()是,如果a包含以下内容的所有元素,b,则将它们放入同一集合不会改变大小。

例如,如果const a = [1,2,3,4]const b = [1,2],则new Set([...a, ...b]) === {1,2,3,4}。如您所见,结果集具有与元素相同的元素a

从那里开始,为了使其更简洁,我们可以将其简化为以下内容:

const isEqualSet = (a, b) => {
  const unionSize = new Set([...a, ...b])
  return unionSize === a.length && unionSize === b.length
}

1

PURE JS(当数组和子数组具有两个以上任意顺序的元素时,也可以使用)。如果字符串包含,用作字符串中未使用的join('-')参数字符(可以是utf)

array1.map(x=>x.sort()).sort().join() === array2.map(x=>x.sort()).sort().join()


0

我们可以使用_.difference函数来查看是否存在任何差异。

function isSame(arrayOne, arrayTwo) {
   var a = _.unique(arrayOne),
       b = _.unique(arrayTwo);

   if (a.length <= b.length) {
      a = arrayTwo;
      b = arrayOne;
      return _.isEmpty(_.difference(a.sort(), b.sort()));
   } else {
      return false;
   }

}

// examples
console.log(isSame([1, 2, 3], [1, 2, 3])); // true
console.log(isSame([1, 2, 4], [1, 2, 3])); // false
console.log(isSame([1, 2], [2, 3, 1])); // false
console.log(isSame([2, 3, 1], [1, 2])); // false

// Test cases pointed by Mariano Desanze, Thanks.
console.log(isSame([1, 2, 3], [1, 2, 2])); // false
console.log(isSame([1, 2, 2], [1, 2, 2])); // true
console.log(isSame([1, 2, 2], [1, 2, 3])); // false

我希望这能帮到您。


5
错误的,您的职能将会得到true解决console.log(isSame([1,2], [2,3,1]));
David Lin

3
谢谢@DavidLin指出。我已做出更改以考虑这种情况。谢谢您,不便之处,敬请原谅。
阿米特什

2
如果长度不同,则无需为a和b切换位置。如果长度不同,那么它们就不能相同了,因此if(arrayOne.lenght!== arrayTwo.lenght)返回false;
亚历克斯(Alex)

1
-1没有这些ab变量。您使用这些变量里面if-then的一部分,而你要做的第一件事有丢弃在第2行,我认为下面一行将工作完全一样加载这些值:return arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());。并且<=也可以改进成===
马里亚诺·德桑兹

1
并且_.difference将返回第一个参数的缺失项,但不会返回第二个参数的缺失项。因此,true当您在2nd中的1st重复项目时,这将错误地返回isSame([1, 2, 3], [1, 2, 2])
马里亚诺·德桑兹

0

编辑:我错过了这个问题的多维方面,所以我留在这里,以防它帮助人们比较一维数组

这是一个老问题,但是我在使用.sort()or 的速度方面遇到问题sortBy(),所以我改用了这个:

function arraysContainSameStrings(array1: string[], array2: string[]): boolean {
  return (
    array1.length === array2.length &&
    array1.every((str) => array2.includes(str)) &&
    array2.every((str) => array1.includes(str))
  )
}

它原本打算很快失败,但出于我的目的,它工作正常。


最后检查真的必要吗? array1.every((str) => array2.includes(str))应该足够了。另外,OP还想使用lodash,您至少应该说出为什么要提出vanillaJS解决方案(...现在我们有了一切并包括了...)。还请提供一个示例,说明如何将函数应用于所提供的问题(二维数组)。
line-o

这是一个好点-我没有解决它的多维方面,而不是lodash的要求。我认为对任何人(像我一样)进行搜索lodash methods to compare arrays without considering order以了解现代Javascript的替代方案都会很有用。第二次检查是必要的,arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])否则将返回true。我将其保留在此处,可能会有所帮助,但我感谢我尚未回答问题
charliematters
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.