如何在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
[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);