如何在JavaScript中比较数组?
我想比较两个数组。。。理想情况下,效率很高。没什么特别的,只要如何在JavaScript中比较数组?,javascript,arrays,json,Javascript,Arrays,Json,我想比较两个数组。。。理想情况下,效率很高。没什么特别的,只要true如果它们相同,就行了,如果不相同,就行false。毫不奇怪,比较运算符似乎不起作用 var a1 = [1,2,3]; var a2 = [1,2,3]; console.log(a1==a2); // Returns false console.log(JSON.stringify(a1)==JSON.stringify(a2)); // Returns true JSON编码每个数组都可以,但是有没有一种更快
true
如果它们相同,就行了,如果不相同,就行false
。毫不奇怪,比较运算符似乎不起作用
var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2); // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2)); // Returns true
JSON编码每个数组都可以,但是有没有一种更快或“更好”的方法可以简单地比较数组而不必遍历每个值?与JSON相同。encode使用join() 唯一的问题是,您是否关心上次比较测试的类型。 如果您关心类型,则必须循环
function checkArrays( arrA, arrB ){
//check if lengths are different
if(arrA.length !== arrB.length) return false;
//slice so we do not effect the orginal
//sort makes sure they are in order
var cA = arrA.slice().sort();
var cB = arrB.slice().sort();
for(var i=0;i<cA.length;i++){
if(cA[i]!==cB[i]) return false;
}
return true;
}
var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];
console.log( checkArrays(a,b) ); //true
console.log( checkArrays(a,c) ); //false
console.log( checkArrays(a,d) ); //false
console.log( checkArrays(a,e) ); //false
函数校验数组(arrA、arrB){
//检查长度是否不同
如果(arrA.length!==arrB.length)返回false;
//切片,这样我们就不会影响原始图像
//排序确保它们是有序的
var cA=arrA.slice().sort();
var cB=arrB.slice().sort();
对于(var i=0;i不清楚“相同”是什么意思。例如,下面的数组a
和b
是否相同(请注意嵌套数组)
这里有一个优化的数组比较函数,它使用严格的等式依次比较每个数组的对应元素,而不递归比较本身就是数组的数组元素,这意味着在上面的示例中,arraysIdentical(a,b)
将返回false
。它适用于一般情况,而基于JSON和join()的解决方案不会:
function arraysIdentical(a, b) {
var i = a.length;
if (i != b.length) return false;
while (i--) {
if (a[i] !== b[i]) return false;
}
return true;
};
要比较数组,请遍历数组并比较每个值:
比较阵列:
您可能会说“但是比较字符串要快得多-没有循环…”那么,您应该注意到有循环。第一个递归循环将数组转换为字符串,第二个比较两个字符串。因此此方法比使用字符串更快
我认为大量的数据应该总是存储在数组中,而不是存储在对象中。但是,如果使用对象,它们也可以进行部分比较。
方法如下:
var arr1 = [1, 2, 3, 4];
var arr2 = [2, 1, 4, 3]; // Loosely equal to 1
var arr3 = [2, 2, 3, 4]; // Not equal to 1
var arr4 = [1, 2, 3, 4]; // Strictly equal to 1
arr1.equals(arr2); // false
arr1.equals(arr2, false); // true
arr1.equals(arr3); // false
arr1.equals(arr3, false); // false
arr1.equals(arr4); // true
arr1.equals(arr4, false); // true
比较对象:
如上所述,两个对象实例永远不会相等,即使它们目前包含相同的数据:
({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666}) //false
这是有原因的,因为例如
但是,如果仅使用对象结构来包含数据,则仍然可以进行比较:
Object.prototype.equals = function(object2) {
//For the first loop, we only check for types
for (propName in this) {
//Check for inherited methods and properties - like .equals itself
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
//Return false if the return value is different
if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
return false;
}
//Check instance type
else if (typeof this[propName] != typeof object2[propName]) {
//Different types => not equal
return false;
}
}
//Now a deeper check using other objects property names
for(propName in object2) {
//We must check instances anyway, there may be a property that only exists in object2
//I wonder, if remembering the checked values from the first loop would be faster or not
if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
return false;
}
else if (typeof this[propName] != typeof object2[propName]) {
return false;
}
//If the property is inherited, do not check any more (it must be equa if both objects inherit it)
if(!this.hasOwnProperty(propName))
continue;
//Now the detail check and recursion
//This returns the script back to the array comparing
/**REQUIRES Array.equals**/
if (this[propName] instanceof Array && object2[propName] instanceof Array) {
// recurse into the nested arrays
if (!this[propName].equals(object2[propName]))
return false;
}
else if (this[propName] instanceof Object && object2[propName] instanceof Object) {
// recurse into another objects
//console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
if (!this[propName].equals(object2[propName]))
return false;
}
//Normal value comparison for strings and numbers
else if(this[propName] != object2[propName]) {
return false;
}
}
//If everything passed, let's say YES
return true;
}
但是,请记住,这是用于比较类似JSON的数据,而不是类实例和其他内容。如果要比较更复杂的对象,请查看。
要使用Array.equals
执行此操作,必须稍微编辑原始函数:
...
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
return false;
}
/**REQUIRES OBJECT COMPARE**/
else if (this[i] instanceof Object && array[i] instanceof Object) {
// recurse into another objects
//console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
if (!this[i].equals(array[i]))
return false;
}
else if (this[i] != array[i]) {
...
我发了一封信
额外好处:带有indexOf
和包含
用于在嵌套数组中搜索特定对象的有用函数,可在此处找到:在我的示例中,比较数组仅包含数字和字符串。此函数将显示数组是否包含相同的元素
function are_arrs_match(arr1, arr2){
return arr1.sort().toString() === arr2.sort().toString()
}
让我们测试一下
arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]
console.log (are_arrs_match(arr1, arr2)) //true
console.log (are_arrs_match(arr1, arr3)) //false
以下是我的解决方案:
/**
* Tests two data structures for equality
* @param {object} x
* @param {object} y
* @returns {boolean}
*/
var equal = function(x, y) {
if (typeof x !== typeof y) return false;
if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
if (typeof x === 'object') {
for (var p in x) if (x.hasOwnProperty(p)) {
if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
if (typeof x[p] !== typeof y[p]) return false;
if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
if (x[p] !== y[p]) return false;
}
} else return x === y;
return true;
};
可以使用任何嵌套的数据结构,并且显然会忽略对象的方法。甚至不要考虑使用此方法扩展Object.prototype,当我尝试过一次时,jQuery崩溃了;)
对于大多数数组,它仍然比大多数序列化解决方案快。它可能是对象记录数组的最快比较方法。基于TomášZato的答案,我同意仅迭代数组是最快的。此外(如其他人所述),该函数应称为equals/equal,而不是compare。有鉴于此,我修改了该函数以处理相似性比较数组,即它们具有相同的元素,但顺序不一致,以供个人使用,并认为我会将其放在这里供大家查看
Array.prototype.equals = function (array, strict) {
if (!array)
return false;
if (arguments.length == 1)
strict = true;
if (this.length != array.length)
return false;
for (var i = 0; i < this.length; i++) {
if (this[i] instanceof Array && array[i] instanceof Array) {
if (!this[i].equals(array[i], strict))
return false;
}
else if (strict && this[i] != array[i]) {
return false;
}
else if (!strict) {
return this.sort().equals(array.sort(), true);
}
}
return true;
}
我还编写了一个包含函数和示例的快速JSFIDLE:
虽然这只适用于标量数组(请参见下面的注释),但它很短:
array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
Rr,在带有箭头函数的ECMAScript 6/CoffeeScript/TypeScript中:
array1.length === array2.length && array1.every((value, index) => value === array2[index])
(注意:此处的“标量”表示可以使用=
直接比较的值。因此:数字、字符串、引用对象、引用函数。有关比较运算符的更多信息,请参阅)
更新
根据我从评论中读到的内容,对数组进行排序并进行比较可能会得到准确的结果:
const array2Sorted = array2.slice().sort();
array1.length === array2.length && array1.slice().sort().every(function(value, index) {
return value === array2Sorted[index];
});
例如:
然后,上面的代码将给出true
我喜欢将下划线库用于数组/对象繁重的编码项目…在下划线和Lodash中,无论您是比较数组还是对象,它看起来都是这样的:
_.isEqual(array1, array2) // returns a boolean
_.isEqual(object1, object2) // returns a boolean
我认为这是使用JSON stringify实现的最简单方法,在某些情况下,这可能是最好的解决方案:
JSON.stringify(a1) === JSON.stringify(a2);
这会将对象a1
和a2
转换为字符串,以便对它们进行比较。在大多数情况下,顺序很重要,因为这样可以使用上述答案之一所示的排序算法对对象进行排序
请注意,您不再比较对象,而是比较对象的字符串表示形式。它可能不完全是您想要的。如果您使用的是类似于断言库的测试框架,则可以使用相等来比较数组
expect(a1).to.deep.equal(a2)
只有当数组在相应的索引处具有相等的元素时,才会返回true。我们可以通过函数方式,使用every
()
实用的方法
我认为说特定的实现是“正确的方式”是错误的™" Tomáš的解决方案明显优于基于字符串的数组比较,但这并不意味着它客观上是“正确的”“。到底什么是正确的?它是最快的吗?它是最灵活的吗?它是最容易理解的吗?它是调试最快的吗?它使用的操作最少吗?它有任何副作用吗?没有一个解决方案可以拥有最好的一切。”
汤姆·亚什可以说他的解决方案很快,但我会的
array1.length === array2.length && array1.every((value, index) => value === array2[index])
const array2Sorted = array2.slice().sort();
array1.length === array2.length && array1.slice().sort().every(function(value, index) {
return value === array2Sorted[index];
});
array1 = [2,3,1,4];
array2 = [1,2,3,4];
_.isEqual(array1, array2) // returns a boolean
_.isEqual(object1, object2) // returns a boolean
JSON.stringify(a1) === JSON.stringify(a2);
expect(a1).to.deep.equal(a2)
function compareArrays(array1, array2) {
if (array1.length === array2.length)
return array1.every((a, index) => a === array2[index])
else
return false
}
// test
var a1 = [1,2,3];
var a2 = [1,2,3];
var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']
console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false
// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
x === undefined && y === undefined
? true
: Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)
// equal :: a -> a -> Bool
const equal = x => y =>
x === y // notice: triple equal
// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
arrayCompare (equal)
const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2) && (3 === 3) //=> true
const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs)) //=> false
// (1 === '1') //=> false
// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
x == y // notice: double equal
// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
arrayCompare (looseEqual)
const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys)) //=> true
// (1 == '1') && (2 == '2') && (3 == '3') //=> true
// isArray :: a -> Bool
const isArray =
Array.isArray
// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
arrayCompare (a => b =>
isArray (a) && isArray (b)
? arrayDeepCompare (f) (a) (b)
: f (a) (b))
const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3') //=> false
console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3') //=> true
// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
arrayDeepCompare (equal)
// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
arrayDeepCompare (looseEqual)
// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
x.id !== undefined && x.id === y.id
// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
arrayCompare (idEqual)
const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2) //=> true
const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6) //=> false
const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys)) //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true
// gt :: Number -> Number -> Bool
const gt = x => y =>
x > y
// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)
const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys)) //=> true
// (5 > 2) && (10 > 4) && (20 > 8) //=> true
const zs = [6,12,24]
console.log (arrayGt (xs) (zs)) //=> false
// (5 > 6) //=> false
arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)
arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false
const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true
var i = a1.length;
while (i--) {
if (a1[i] !== a2[i]) return false;
}
return true
a1.every((v,i)=> v === a2[i]);
a1.reduce((a, b) => a && a2.includes(b), true);
a1.join('') === a2.join('');
a1.toString() === a2.toString();
a1 == a2.toString();
JSON.stringify(a1) === JSON.stringify(a2);
function areEqual(a, b) {
if ( a.length != b.length) {
return false;
}
return a.filter(function(i) {
return !b.includes(i);
}).length === 0;
}
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)
[ Set { 'a', 'b', 'c' } ]
const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)
[ 'a', 'b', 'c' ]
function equals(a, b) {
if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
return false;
}
var isDifferent = a.some(function (element, index) {
return element !== b[index];
});
return !isDifferent;
}
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ? array.push(collection[i]) : null
var arr1 = [1,2,3];
var arr2 = [1,2,3];
function compare(arr1,arr2)
{
if((arr1 == arr2) && (arr1.length == arr2.length))
return true;
else
return false;
}
var isBool = compare(arr1.sort().join(),arr2.sort().join());
JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true
JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false
JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false
JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false
JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true
JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false
JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false
JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true
//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
if (a === b) return true
if (a == null || b == null) return false
if (a.length != b.length) return false
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false
}
return true
}
//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
return JSON.stringify(a) === JSON.stringify(b)
}
it('arraysEqual', function () {
let a = [1,2]
let b = [1,2]
let c = [2,3]
let d = [2, 3]
let e = ['car','apple','banana']
let f = ['car','apple','banana']
let g = ['car','apple','banan8']
expect(arraysEqual(a, b)).to.equal(true)
expect(arraysEqual(c, d)).to.equal(true)
expect(arraysEqual(a, d)).to.equal(false)
expect(arraysEqual(e, f)).to.equal(true)
expect(arraysEqual(f, g)).to.equal(false)
})
it('arraysDeepEqual', function () {
let a = [1,2]
let b = [1,2]
let c = [2,3]
let d = [2, 3]
let e = ['car','apple','banana']
let f = ['car','apple','banana']
let g = ['car','apple','banan8']
let h = [[1,2],'apple','banan8']
let i = [[1,2],'apple','banan8']
let j = [[1,3],'apple','banan8']
expect(arraysDeepEqual(a, b)).to.equal(true)
expect(arraysDeepEqual(c, d)).to.equal(true)
expect(arraysDeepEqual(a, d)).to.equal(false)
expect(arraysDeepEqual(e, f)).to.equal(true)
expect(arraysDeepEqual(f, g)).to.equal(false)
expect(arraysDeepEqual(h, i)).to.equal(true)
expect(arraysDeepEqual(h, j)).to.equal(false)
})
In a simple way uning stringify but at same time thinking in complex arrays:
**Simple arrays**:
var a = [1,2,3,4];
var b = [4,2,1,4];
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true
**Complex arrays**:
var a = [{id:5,name:'as'},{id:2,name:'bes'}];
var b = [{id:2,name:'bes'},{id:5,name:'as'}];
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true
**Or we can create a sort function**
function sortX(a,b) {
return a.id -b.id; //change for the necessary rules
}
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true
const a = [1, 2, 3];
const b = [1, 2, 'test'];
const a_string = Array.isArray(a) && `${a}`;
const b_string = Array.isArray(b) && `${b}`;
const result = (a === b);
console.log(result);
a1==''+a2
arrOne.length === arrTwo.length && arrOne.filter((currVal, idx) => currVal !== arrTwo[idx]).length === 0
const array1 = [1,3,2,4,5];
const array2 = [1,3,2,4,5];
const isInArray1 = array1.every(item => array2.find(item2 => item===item2))
const isInArray2 = array2.every(item => array1.find(item2 => item===item2))
const isSameArray = array1.length === array2.length && isInArray1 && isInArray2
console.log(isSameArray); //true
[1, 2, 3].equals([1, 2, 3]) // evaluates to true
[1, 2, undefined].equals([1, 2, 3]) // evaluates to false
[1, [2, [3, 4]]].equals([1, [2, [3, 4]]]) // evaluates to true
import {isEqual} from "lodash";
const isTwoArraysEqual = isEqual(array1, array2);