代码之家  ›  专栏  ›  技术社区  ›  Foobar

两个空数组不相等[duplicate]

  •  0
  • Foobar  · 技术社区  · 6 年前

    我想比较两个数组。。。理想的,高效的。没什么特别的,只是 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
    

    0 回复  |  直到 9 年前
        1
  •  5
  •   Mr. Durga prasad patra    6 年前

    要比较数组,请遍历数组并比较每个值:

    比较数组:

    // Warn if overriding existing method
    if(Array.prototype.equals)
        console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
    // attach the .equals method to Array's prototype to call it on any array
    Array.prototype.equals = function (array) {
        // if the other array is a falsy value, return
        if (!array)
            return false;
    
        // compare lengths - can save a lot of time 
        if (this.length != array.length)
            return false;
    
        for (var i = 0, l=this.length; i < l; i++) {
            // 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;       
            }           
            else if (this[i] != array[i]) { 
                // Warning - two different object instances will never be equal: {x:20} != {x:20}
                return false;   
            }           
        }       
        return true;
    }
    // Hide method from for-in loops
    Object.defineProperty(Array.prototype, "equals", {enumerable: false});
    

    用法:

    [1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false;
    [1, "2,3"].equals([1, 2, 3]) === false;
    [1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true;
    [1, 2, 1, 2].equals([1, 2, 1, 2]) === true;
    

    但是比较字符串要快得多-没有循环。。。 “好吧,那么你应该注意到有循环。第一个递归循环将数组转换为字符串,第二个循环比较两个字符串。这种方法 比使用字符串快 .


    方法如下:

    比较对象:

    我在上面已经说过,那两个物体 永远不会相等,即使它们包含相同的数据:

    ({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false
    

    这是有原因的,例如 private variables within objects.

    但是,如果只使用对象结构来包含数据,则仍然可以进行比较:

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

    this answer and it's superlong function .
    使这工作 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]) {
    ...
    

    我做了一个 little test tool for both of the functions .

    indexOf contains

    Samy Bencherif has prepared 对于在嵌套数组中搜索特定对象的情况,可以使用以下函数: https://jsfiddle.net/SamyBencherif/8352y6yw/

        2
  •  5
  •   Kamil Kiełczewski    5 年前

    虽然这只适用于标量数组(请参见下面的注释),但它很短:

    array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
    

    array1.length === array2.length && array1.every((value, index) => value === array2[index])
    

    (注意:这里的“标量”是指可以使用 === . 所以:数字,字符串,引用的对象,引用的函数。看到了吗 the MDN reference 有关比较运算符的详细信息)。

    根据我从评论中读到的,对数组进行排序和比较可能会得到准确的结果:

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

    那么上面的代码会给出 true

        3
  •  5
  •   CertainPerformance    5 年前

    _.isEqual(array1, array2)   // returns a boolean
    _.isEqual(object1, object2) // returns a boolean
    
        4
  •  3
  •   AL-zami    7 年前

    JSON.stringify(a1) === JSON.stringify(a2);
    

    这将转换对象 a1 a2 为了便于比较。在大多数情况下,顺序是很重要的,因为它可以使用上述答案中所示的排序算法对对象进行排序。

        5
  •  3
  •   Pedro Bustamante    6 年前

    我认为,如果一个特定的实现仅仅是“正确的”(“正确的”)而不是“错误的”解决方案,那么说它是“正确的”是错误的。Tom的解决方案明显优于基于字符串的数组比较,但这并不意味着它在客观上是“正确的”。是什么 正确的

    汤姆可以说他的解决方案很快,但我也认为这是不必要的复杂。它试图成为一个适用于所有数组(无论是否嵌套)的一体式解决方案。事实上,它甚至不仅仅接受数组作为输入,而且仍然试图给出一个“有效”的答案。


    泛型提供了可重用性

    arrayCompare 只与单步执行数组有关的过程。在此基础上,我们将构建其他基本的比较函数,如 arrayEqual arrayDeepEqual

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

    在我看来,最好的代码甚至不需要注释,这也不例外。这里发生的事情太少了,你几乎可以毫不费力地理解这个过程的行为。当然,有些ES6语法现在对您来说可能是陌生的,但这只是因为ES6相对较新。

    阵列比较 取比较函数, f ,和两个输入数组, xs ys . 在大多数情况下,我们所做的就是打电话 f (x) (y) 对于输入数组中的每个元素。我们提早回来 false f && 的短路评估。所以,是的,这意味着比较器可以提前停止迭代,并在不必要时防止遍历输入数组的其余部分。


    接下来,使用我们的 阵列比较 函数,我们可以轻松地创建我们可能需要的其他函数。我们从小学开始

    // 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
    

    就这么简单。 arrayEqual公司 阵列比较 以及一个比较函数 a b 使用 ===

    注意,我们还定义了 equal 阵列比较


    松散的比较

    我们也可以很容易地定义 arrayLooseEqual 使用 == 1 (编号)至 '1' (字符串),结果将是 true

    // 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
    

    就这么简单。我们用 另一个 高阶函数。这次我们要包装了 阵列比较 使用自定义比较器检查 是数组。如果是,请重新申请 arrayDeepCompare 否则比较 到用户指定的比较器( f ). 这使我们能够将深度比较行为与实际比较单个元素的方式分开。如上面的例子所示,我们可以用 平等的 looseEqual

    因为 阵列比较 是curried,我们也可以像前面的例子一样部分地应用它

    // arrayDeepEqual :: [a] -> [a] -> Bool
    const arrayDeepEqual =
      arrayDeepCompare (equal)
    
    // arrayDeepLooseEqual :: [a] -> [a] -> Bool
    const arrayDeepLooseEqual =
      arrayDeepCompare (looseEqual)
    

    明确地 根据需要,为我的数组选择浅或深比较。


    现在如果你有一个对象数组或其他什么呢?如果每个对象都具有相同的数组,那么您可能会认为这些数组是“相等的” id

    // 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
    

    任何 对象类型;甚至是自定义对象。为了支持这种平等测试,Tom的解决方案需要完全重写

    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
    

    任意比较(示例)

    x 大于每个 y

    // 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
    

    少即是多

    你可以看到我们用更少的代码做的更多。没什么复杂的 阵列比较

    全部使用一个程序 阵列比较 . 也许你甚至可以想象一个 RegExp

    它是最快的吗?不。但可能也不需要。如果速度是衡量代码质量的唯一标准,那么很多真正优秀的代码都会被丢弃——这就是为什么我要调用这种方法 . 或者更公平地说, A 实用的方法。这个描述适合这个答案,因为我并不是说这个答案只在与其他答案比较时才实用;它是客观真实的。我们已经达到了高度的实用性,只需要很少的代码,很容易推理。没有其他代码可以说我们没有获得这个描述。

    你认为这是“正确”的解决方案吗?就这样吧


    编辑

    我以前的回答更侧重于分解 arrayEqual公司 做一些小程序。这是一个有趣的练习,但并不是解决这个问题的最好(最实用)方法。如果你感兴趣,你可以看到这个修订历史。

        6
  •  3
  •   jpthesolver2    5 年前

    本着最初问题的精神:

    高效 没有什么 设想 ,如果它们相同,则为真,否则为假。

    results (快到慢):

    while

    var i = a1.length;
    while (i--) {
        if (a1[i] !== a2[i]) return false;
    }
    return true
    

    every (69%) 用户2782196

    a1.every((v,i)=> v === a2[i]);
    

    reduce 德伊斯

    a1.reduce((a, b) => a && a2.includes(b), true);
    

    join &安培; toString (78%) 作者:Gaizka Allende&vivek

    a1.join('') === a2.join('');
    
    a1.toString() === a2.toString();
    

    half toString (90%) 作者:Victor Palomo

    a1 == a2.toString();
    

    stringify

    JSON.stringify(a1) === JSON.stringify(a2);
    

    注意 下面的示例假设数组是排序的一维数组。 .length a1.length === a2.length

    有趣的是,看到人们在投票中获得了对这个问题完全合理的答案,乐此不疲的约翰·韦恩斯。

        7
  •  3
  •   undefined Rather not say    5 年前

    不清楚你说的“完全相同”是什么意思。例如,数组 a b

    var a = ["foo", ["bar"]], b = ["foo", ["bar"]];
    

    这里有一个优化的数组比较函数,它使用严格的相等来比较每个数组的对应元素,并且不对本身是数组的数组元素进行递归比较,这意味着对于上述示例, arraysIdentical(a, b) 会回来的 false . 它适用于一般情况,即JSON-and 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;
    };
    
        8
  •  2
  •   Pedro Rodrigues    7 年前

    根据tomzato的回答,我同意只迭代数组是最快的。另外(就像其他人已经说过的那样),函数应该被称为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;
    }
    

    例子:

    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
    

    我还编写了一个快速的jsfiddle函数和这个示例:
    http://jsfiddle.net/Roundaround/DLkxX/