【问题标题】:How to know if two arrays have the same values如何知道两个数组是否具有相同的值
【发布时间】:2011-09-07 22:08:33
【问题描述】:

我有这两个数组:一个填充来自 ajax 请求的信息,另一个存储用户单击的按钮。我使用此代码(我填写了示例编号):

var array1 = [2, 4];
var array2 = [4, 2]; //It cames from the user button clicks, so it might be disordered.
array1.sort(); //Sorts both Ajax and user info.
array2.sort();
if (array1==array2) {
    doSomething();
}else{
    doAnotherThing();
}

但它总是给出false,即使两个数组相同,但名称不同。 (我在 Chrome 的 JS 控制台中检查了这个)。那么,有什么方法可以知道这两个数组是否包含相同的内容?为什么给false?如何知道第一个数组中的哪些值不在第二个数组中?

【问题讨论】:

标签: javascript arrays compare


【解决方案1】:
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { //To test values in nested arrays
            if (!this[i].compare(testArr[i])) return false;
        }
        else if (this[i] !== testArr[i]) return false;
    }
    return true;
}

var array1 = [2, 4];
var array2 = [4, 2];
if(array1.sort().compare(array2.sort())) {
    doSomething();
} else {
    doAnotherThing();
}

也许?

【讨论】:

  • 谢谢!它可以按预期工作。我稍微修改了函数,这样我也可以知道有多少不匹配。
  • 假 [2,4] [4,2]。
  • @SurazKhanal 还是需要排序
【解决方案2】:

当您比较这两个数组时,您是在比较表示数组的对象,而不是内容。

您必须使用函数来比较两者。您可以编写自己的代码,简单地循环一个并在检查长度是否相同后将其与另一个进行比较。

【讨论】:

    【解决方案3】:

    如果您的数组项不是对象-例如,如果它们是数字或字符串,您可以比较它们的连接字符串以查看它们是否以任何顺序具有相同的成员-

    var array1= [10, 6, 19, 16, 14, 15, 2, 9, 5, 3, 4, 13, 8, 7, 1, 12, 18, 11, 20, 17];
    var array2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
    
    if(array1.sort().join(',')=== array2.sort().join(',')){
        alert('same members');
    }
    else alert('not a match');
    

    【讨论】:

    • 这适用于具有唯一标识 toString 值的原语或对象,但不适用于任何对象。
    • 谨防空项目和排序。在我的情况下,我最终使用字符串进行比较,例如“,2,2,3”和“2,2,3”,这当然不是严格相等的。
    • 对于字符串可能会失败,即['a', 'b']['a,b']。我只会将这种技术推荐用于小型一次性脚本。
    • 嗨 kennebec,你能告诉我如何将匹配的内容保存到另一个数组中
    • @alex -- 在我的情况下,字符串中允许使用逗号,但不允许使用分号,所以我使用了 ';'加入而不是逗号
    【解决方案4】:

    如果你使用Prototype Framework,你可以使用数组的intersect方法找出它们是否相同(不分先后):

    var array1 = [1,2];
    var array2 = [2,1];
    
    if(array1.intersect(array2).length === array1.length) {
        alert("arrays are the same!");
    }
    

    【讨论】:

    • 这不起作用 - [1,2].intersect([1,2,3]).length === [1,2].length 返回 true。你也应该比较原始数组的长度,我已经编辑了帖子来演示。
    • 实际上我刚刚意识到我建议的编辑在重复的情况下不起作用......例如它将为 array1 = [1,1,2]; array2 = [1,1,2]; 返回 false ...该输入的原始答案不会失败。
    • 你可以用_.difference(array1, array2).length;做相反的事情
    【解决方案5】:

    对象相等检查:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

    上述测试也适用于对象数组,在这种情况下使用http://www.w3schools.com/jsref/jsref_sort.asp中记录的排序函数

    对于具有扁平 JSON 模式的小型数组可能就足够了。

    【讨论】:

      【解决方案6】:

      如果您只想检查两个数组是否具有相同的值(不管每个值的出现次数和顺序),您可以使用lodash

      _.isEmpty(_.xor(array1, array2))
      

      简短、简单、漂亮!

      【讨论】:

      • 我似乎在下划线文档中找不到xor?你在考虑 IOdash 吗?
      • 这只适用于整数。问题是“两个数组”而不是“两个整数数组”
      • 是的。在 2021 年并确认它适用于字符串数组。 :-)
      【解决方案7】:

      我在游戏项目中有简单的整数值
      每个数组中的值数量较少,也需要原始数组保持不变
      所以,我做了下面的,它工作得很好。 (代码编辑粘贴到这里)

      var sourceArray = [1, 2, 3];
      var targetArray = [3, 2, 1];
      
      if (sourceArray.length !== targetArray.length) {
          // not equal
          // did something
          return false;
      }
      
      var newSortedSourceArray = sourceArray.slice().sort();
      var newSortedTargetArray = targetArray.slice().sort();
      
      if (newSortedSourceArray.toString() !== newSortedTargetArray.toString()) { // MAIN CHECK
          // not equal
          // did something
          return false;
      }
      else {
          // equal
          // did something
          // continued further below
      }
      
      // did some more work
      
      return true;
      

      希望对您有所帮助。

      【讨论】:

        【解决方案8】:

        为什么您的代码不起作用

        JavaScript 有 primitive data types 和非原始数据类型。

        对于原始数据类型,===== 检查条形两侧的东西是否具有相同的值。这就是为什么1 === 1 是正确的。

        对于数组等非原始数据类型,===== 检查引用相等性。也就是说,他们检查arr1arr2 是否是同一个对象。在您的示例中,两个数组以相同的顺序具有相同的对象,但不等价。

        解决方案

        两个数组 arr1arr2 具有相同的成员当且仅当:

        • arr2 中的所有内容都在 arr1

        • arr1 中的所有内容都在arr2

        所以这可以解决问题(ES2016):

        const containsAll = (arr1, arr2) => 
                        arr2.every(arr2Item => arr1.includes(arr2Item))
                        
        const sameMembers = (arr1, arr2) => 
                                containsAll(arr1, arr2) && containsAll(arr2, arr1);
        
        sameMembers(arr1, arr2); // `true`
        

        使用Underscore 的第二个解决方案更接近您想要做的:

        arr1.sort();
        arr2.sort();
        
        _.isEqual(arr1, arr2); // `true`
        

        之所以有效,是因为 isEqual 检查“深度相等”,这意味着它不仅仅查看引用相等并比较值。

        第三个问题的解答

        您还问如何找出arr1 中的哪些内容不包含在arr2 中。

        这样就可以了(ES2015):

        const arr1 = [1, 2, 3, 4];
        const arr2 = [3, 2, 1];
        
        arr1.filter(arr1Item => !arr2.includes(arr1Item)); // `[4]`
        

        你也可以使用Underscore的difference:方法:

        _.difference(arr1, arr2); // `[4]`
        

        更新

        查看@Redu 的评论——我的解决方案是sameMembers,但您可能想到的是sameMembersInOrderalso-known-as deepEquals

        更新 2

        如果你不关心数组成员的顺序,ES2015+ 的Set 可能是比Array 更好的数据结构。请参阅MDN notes on how to implement isSuperset and difference 使用危险的猴子补丁。

        更新 3

        如果顺序无关紧要,最好还是使用集合。但是如果你必须使用数组,这个解决方案的时间复杂度比我之前给出的要好:

        function sameMembers(arr1, arr2) {
            const set1 = new Set(arr1);
            const set2 = new Set(arr2);
            return arr1.every(item => set2.has(item)) &&
                arr2.every(item => set1.has(item))
        }
        

        【讨论】:

        • 您的解决方案有误。 “两个数组 arr1 和 arr2 具有相同的成员当且仅当:arr2 中的所有内容都在 arr1 中并且 arr1 中的所有内容都在 arr2 中”这也是错误的。这是一个数组而不是一个集合。所以sameMembers([1,1,2],[2,1,2]);应该返回false。
        • @Redu 猜测这取决于“相同成员”的含义——我认为它的意思是“拥有相同的成员”。在我看来,sameMembers([1,1,2],[2,1,2]) 应该返回 truesameMembersInOrder([1,1,2],[2,1,2]) AKA deepEquals([1,1,2],[2,1,2]) 应该返回 false
        • 您的第三个解决方案 arr1.filter... 仅适用于检查 arr2 是否具有 arr1 的所有元素,但反之亦然。
        • 我的麻袋里有 2 个苹果和 1 个橙子。你的麻袋里有 2 个橙子和 1 个苹果。他们没有相同的成员。 [1,1,2] 和 [2,1,2] 不是同一个成员..
        • @gman,那些不是橙子和苹果,它们是数字,还有1 === 1。但听起来您想检查两个数组是否以相同的顺序具有相同的项目:在这种情况下,您将需要不同的算法。
        【解决方案9】:

        对数组进行排序并一一比较它们的值。

        function arrayCompare(_arr1, _arr2) {
            if (
              !Array.isArray(_arr1)
              || !Array.isArray(_arr2)
              || _arr1.length !== _arr2.length
              ) {
                return false;
              }
            
            // .concat() to not mutate arguments
            const arr1 = _arr1.concat().sort();
            const arr2 = _arr2.concat().sort();
            
            for (let i = 0; i < arr1.length; i++) {
                if (arr1[i] !== arr2[i]) {
                    return false;
                 }
            }
            
            return true;
        }
        

        【讨论】:

        • 排序需要 nlog(n) 时间。你不需要排序。这个答案stackoverflow.com/a/55614659/3209523 在线性时间内有效。
        • 使用打字稿 Array.isArray() 导致错误,删除它工作正常。
        • @canbax 当数组为 [1,2] 和 [1,1,2] 时,链接中的函数返回 true,在我的情况下,它们是 2 个不同的数组。虽然这个函数对这两个不同的数组说假。
        • @LukasLiesis 问题问"if two arrays have the same values"。所以不是问它们是否相同。我知道这是在询问数组是否相等。 en.wikipedia.org/wiki/Set_(mathematics)[1,2][1,1,2] 是相等的集合。它们都包含12
        • @canbax:您链接到的答案可能不是此处 OP 的正确答案,但它非常适合我的用例 :)
        【解决方案10】:

        请检查此答案

        var arr1= [12,18];
        var arr2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
        for(i=0;i<arr1.length;i++)
        {
        var array1=arr1[i];
        for(j=0;j<arr2.length;j++)
        {
            var array2=arr2[j];
            if(array1==array2)
            {
        return true;
            }
        }
        }
        

        【讨论】:

        • 这在功能上等同于this answer,除了一些错误。首先,这应该全部包含在一个函数中,否则return 将无效。其次,您应该检查已排序的数组,因为[1,2][2,1] 将被检测为不相同。第三也是最重要的,这实际上只会检查 some element 是否相同。条件应该是if (array1!==array2) {return false;}。也许这对您将来有帮助!
        • 作为额外的注释,请尝试使用缩进来更好地理解代码流,以及更清晰的变量名称。例如:array1array2 可以重命名为 elem1elem2。这两个技巧将在未来为您省去很多麻烦!
        • 进一步检查,为什么是双循环?两个数组的长度应该相同,否则直接不相等。这样,您只能使用一个循环。现在,此代码检查第一个数组的 any 元素是否在第二个数组中的 anywhere 中。检查this answer 看看你应该如何实现它。祝你的 JavaScript 之旅好运!
        【解决方案11】:

        使用 ES6

        我们将使用 Ramda 的 equals 函数,但我们可以使用 Lodash 或 Underscore 的 isEqual

        const R = require('ramda');
        
        const arraysHaveSameValues = (arr1, arr2) => R.equals( [...arr1].sort(), [...arr2].sort() )
        

        使用扩展运算符,我们避免改变原始数组,并保持函数纯净。

        【讨论】:

        • 我看不出这是如何基于 ES6 的。关键是在排序之前克隆数组,这可以使用arr1.slice().sort() 完成。最终是 Ramda 使用了所有的工作。
        【解决方案12】:

        我们的目标基本上是检查两个数组是否相等。 set 是数学定义的集合。最快的渐近排序需要 O(nlog(n)) 时间。因此,如果对数组进行排序,则至少需要 O(nlog(n)) 时间。但是您可以更快地完成这项任务,使用字典数据结构渐近需要 O(n) 时间(平均情况不是最坏情况)。在 JS 中,字典只是一个带有键和值的对象。

        /** assumes array elements are primitive types
        * check whether 2 arrays are equal sets.
        * @param  {} a1 is an array
        * @param  {} a2 is an array
        */
        function areArraysEqualSets(a1, a2) {
          const superSet = {};
          for (const i of a1) {
            const e = i + typeof i;
            superSet[e] = 1;
          }
        
          for (const i of a2) {
            const e = i + typeof i;
            if (!superSet[e]) {
              return false;
            }
            superSet[e] = 2;
          }
        
          for (let e in superSet) {
            if (superSet[e] === 1) {
              return false;
            }
          }
        
          return true;
        }
        

        请注意,此函数适用于原始类型的数组,并假定 a1a2 是数组。

        【讨论】:

        • 这不处理其中一个数组中有重复值的情况。例如areArraysEqualSets([1, 2, 2], [1, 2])
        • 确实如此。我在控制台中尝试过。 areArraysEqualSets([1, 2, 2], [1, 2]) true 在数学上它们是相等的集合。
        • 这不是问题的答案。这个问题不是关于集合的,而是关于数组的。 [1,2,2] 和 [1,2] 不是同一个数组。此答案将被删除为“不是答案”
        • @gman 你错了,问题标题是How to know if two arrays have the same values。重复值并不是很清楚。但我知道他基本上要求whether 2 arrays are equal sets. 所以我仍然认为我的回答是正确的,也是最快的工作算法。 (在我写完我的答案后没有检查新答案)。另外,请注意,我不是在谈论 javascript 中的 Set 类。我指的是理论集合。这是一个数学定义。我已经给出了我所指内容的链接
        • 好吧,我们可以说他们不是根据他们选择的答案来寻找“相同的集合成员”。他们没有选择“套装”解决方案。至于最快,it depends
        【解决方案13】:

        很久以后才回答,但希望这对寻求简单解决方案的人和现代新手有所帮助。

        现在我们可以使用多个库来实现这一点,例如lodashunderscore 等(由于简单、多种功能和高使用率,这些现在已成为项目的一部分)

        您可以使用 lodash 库中的交集。

        _.intersection(['2-1', '1'], ['2-2', '3-1', '2-1']); 
        // => ['2-1']
        

        这适用于任何数据类型..

        【讨论】:

          【解决方案14】:

          如果您想比较两个数组并检查两个数组中是否有相同的对象,它将起作用。 示例:

          Array1 = [a,b,c,d]
          Array2 = [d,e,f,g]

          这里,'d' 在两个数组中都很常见,所以这个函数将返回真值。

            cehckArray(array1, array2) {
              for (let i = 0; i < array1.length; i++) {
                for (let j = 0; j < array2.length; j++) {
                  if (array1[i] === array2[j]) {
                    return true;
                  }
                }
              }
              // Return if no common element exist 
              return false;
            }
          

          【讨论】:

            【解决方案15】:

            这个呢? ES 2017 我想:

            const array1 = [1, 3, 5];
            const array2 = [1, 5, 3];
            
            const isEqual = (array1.length === array2.length) && (array1.every(val => array2.includes(val)));
            console.log(isEqual);

            第一个条件检查两个数组是否具有相同的长度,第二个条件检查第一个数组是否是第二个数组的子集。结合这 2 个条件应该会比较这 2 个数组的所有项,而不管元素的顺序如何。

            上面的代码只有在两个数组都有不重复项的情况下才有效。

            【讨论】:

            • 请注意,此解决方案的运行时间为 O(n²),而此问题可以通过使用额外空间的 O(n) 运行时间来解决。
            • 我认为如果说 array1 有重复的条目,这将给出一个误报。在数组中,不保证不重复。在上面的示例中,如果数组 1 是 [1,1,5],它将返回 true。
            • 对象数组怎么查?
            【解决方案16】:

            您可以使用reduce 代替循环来显得聪明,但有可能让您的开发人员认为您是个聪明人。

            function isArrayContentSame(a, b) {
              if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
                a = a.concat().sort()
                b = b.concat().sort()
                return a.reduce((acc,e,i) => acc && e === b[i], true)
              } else {
                return false;
              }
            }
            

            【讨论】:

              【解决方案17】:

              使用 ES6 实现浅层相等的简单解决方案:

              const arr1test = arr1.slice().sort()
              const arr2test = arr2.slice().sort()
              const equal = !arr1test.some((val, idx) => val !== arr2test[idx])
              
              

              创建每个数组的浅表副本并对其进行排序。然后使用some() 循环遍历arr1test 值,检查每个值与arr2test 中具有相同索引的值。如果所有值都相等,则some() 返回false,然后equal 计算结果为true

              也可以使用every(),但它必须循环遍历数组中的每个元素以满足true 结果,而some() 将在找到不相等的值时立即退出:

              const equal = arr1test.every((val, idx) => val === arr2test[idx])
              

              【讨论】:

              • 就像some()一旦匹配就停止执行,every()只要不匹配就停止执行,因此两者之间没有性能差异。此外,您没有检查 arr2 是否包含 arr1 没有的内容,因此此代码无法按预期工作。
              • @Rudey 关于性能(非)问题的注意事项,谢谢。我认为您对 arr2 包含 arr1 中不包含的内容的保留可以通过首先检查数组长度是否相同来处理,不是吗?
              【解决方案18】:

              比较两个数组的简单解决方案:

              var array1 = [2, 4];
              var array2 = [4, 2];
              
              array1.sort();
              array2.sort();
              
              if (array1[0] == array2[0]) {
                  console.log("Success");
              }else{
                  console.log("Wrong");
              }
              

              【讨论】:

                【解决方案19】:

                试试这个

                function arraysEqual(arr1, arr2){
                    if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length)
                        return false;
                
                    return arr1.length==arr1.filter(word => arr2.includes(word)).length;
                }
                

                【讨论】:

                  【解决方案20】:

                  根据接受的答案,我有另一种方法。

                  function compareArrays(array1, array2) {
                  
                      if (
                          !Array.isArray(array1)
                          || !Array.isArray(array2)
                          || array1.length !== array2.length
                      ) return false;
                  
                      var first = array1.sort().map(value => (String(value))).join();
                      var second = array2.sort().map(value => (String(value))).join();
                  
                      return first == second ? true : false;
                  }
                  

                  【讨论】:

                  • 嘿,欢迎来到 StackOverflow!尽管此答案在某些情况下可行,但在某些特定情况下则行不通。首先,请注意 .sort() 会修改原始数组。现在这被认为是不卫生,这就是为什么原始答案首先执行 .concat() 来制作副本。
                  • 第二点,这与 JavaScript 的其余部分不一致。 {foo:"bar"} === {foo:"bar"} 返回 false(它们是两个不同的对象,分别创建);所以 compareArrays([{foo:"bar"}], [{foo:"bar"}]), 也应该返回 false 以保持一致性。但是,对于您的实现,它返回 true,因为对象的字符串表示形式是相同的。这可能是一种期望的行为,也可能不是,但无论如何都要注意。
                  【解决方案21】:

                  比较两个数组的函数,以检查两者是否具有相同的元素。就算是乱七八糟的……

                  这对于简单的数组很有用。 [String,Number,Boolean,null,NaN].

                  我不使用 .sort(),它会修改原始数组。有人说它不好...

                  小心。这个函数是有限的,它不能比较 Objects"[],{}" 或者这些数组中的函数,数组本身就是 Objects。

                     let arraysHasSameElements = (arr1, arr2) => {
                          let count =
                              // returns counting of occurrences.
                              (arr, val) => arr.reduce((count, curr) => (curr === val ? 1 : 0) + count, 0);
                  
                          /* this will return true if lengths of the arrays is equal.
                             then compare them.*/
                          return arr1.length === arr2.length
                  
                              // compare arr1 against arr2.
                              && arr1.reduce((checks, val) =>
                  
                                  /*  creating array of checking if a value has equal amount of occurrences
                                      in both arrays, then adds true 'check'. */
                                  checks.concat(count(arr1, val) === count(arr2, val)), [])
                  
                                  // checking if each check is equal to true, then .every() returns true.
                                  .every(check => check);
                      }
                  
                      let arr1 = ['',-99,true,NaN,21,null,false,'help',-99,'help',NaN], 
                          arr2 = [null,-99,'',NaN,NaN,false,true,-99,'help',21,'help'];
                      arraysHasSameElements(arr1, arr2); //true
                  
                      let arr3 = [false,false,false,false,false,false], 
                          arr4 = [false,false,false,false,false,false]
                      arraysHasSameElements(arr3, arr4); //true
                  
                  
                      // here we have uncommented version.
                      let arraysHasSameElements = (arr1, arr2) => {
                          let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
                          return arr1.length === arr2.length && arr1.reduce((checks, val) =>
                              checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
                      }
                  
                  

                  【讨论】:

                    【解决方案22】:

                    大多数其他解决方案使用排序,O(n*log n),使用库或具有 O(n^2) 复杂度。

                    这是一个纯 Javascript 的解决方案,具有线性复杂度,O(n):

                    /**
                     * Check if two arrays of strings or numbers have the same values
                     * @param {string[]|number[]} arr1
                     * @param {string[]|number[]} arr2
                     * @param {Object} [opts]
                     * @param {boolean} [opts.enforceOrder] - By default (false), the order of the values in the arrays doesn't matter.
                     * @return {boolean}
                     */
                    function compareArrays(arr1, arr2, opts) {
                    
                      function vKey(i, v) {
                        return (opts?.enforceOrder ? `${i}-` : '') + `${typeof v}-${v}`
                      }
                    
                      if (arr1.length !== arr2.length) return false;
                    
                      const d1 = {};
                      const d2 = {};  
                      for (let i = arr1.length - 1; i >= 0; i--) {
                        d1[vKey(i, arr1[i])] = true;
                        d2[vKey(i, arr2[i])] = true;
                      }
                      
                      for (let i = arr1.length - 1; i >= 0; i--) {
                        const v = vKey(i, arr1[i]);
                        if (d1[v] !== d2[v]) return false;
                      }
                    
                      for (let i = arr2.length - 1; i >= 0; i--) {
                        const v = vKey(i, arr2[i]);
                        if (d1[v] !== d2[v]) return false;
                      }
                    
                      return true
                    }
                    

                    测试:

                    arr1= [1, 2]
                    arr2= [1, 2]
                    compareArrays(arr1, arr2) => true
                    compareArrays(arr1, arr2, {enforceOrder: true}) => true
                    -------
                    arr1= [1, 2]
                    arr2= [2, 1]
                    compareArrays(arr1, arr2) => true
                    compareArrays(arr1, arr2, {enforceOrder: true}) => false
                    -------
                    arr1= [2, 1]
                    arr2= [1, 2]
                    compareArrays(arr1, arr2) => true
                    compareArrays(arr1, arr2, {enforceOrder: true}) => false
                    -------
                    arr1= [2, 2]
                    arr2= [1, 2]
                    compareArrays(arr1, arr2) => false
                    compareArrays(arr1, arr2, {enforceOrder: true}) => false
                    -------
                    arr1= [1, 2]
                    arr2= [1, 2, 3]
                    compareArrays(arr1, arr2) => false
                    compareArrays(arr1, arr2, {enforceOrder: true}) => false
                    -------
                    arr1= ["1"]
                    arr2= [1]
                    compareArrays(arr1, arr2) => false
                    compareArrays(arr1, arr2, {enforceOrder: true}) => false
                    -------
                    arr1= ["1", 2]
                    arr2= [2, "1"]
                    compareArrays(arr1, arr2) => true
                    compareArrays(arr1, arr2, {enforceOrder: true}) => false
                    -------
                    arr1= []
                    arr2= []
                    compareArrays(arr1, arr2) => true
                    compareArrays(arr1, arr2, {enforceOrder: true}) => true
                    

                    【讨论】:

                    • 嘿,这是一个很棒的条目!这很令人费解,但确实有道理。我有一个问题:我对大 O 表示法不是很熟悉,但这个算法肯定是 O(2n) 吗?不过不要认为这有很大的不同。
                    • @CarlosPrecioso 这是正确的,O(2n) = O(n)。复杂度乘以constant factor 不会改变
                    • 这不处理 compareArrays(['1'], [1])compareArrays([2, 2], [1, 2]) 之类的情况
                    • @SC1000 我的示例只有字符串或数字数组。
                    • @SC1000 确实如此。在每个示例中,数组具有不同的值,但函数返回 true。将 ['1'] 与 [1] 进行比较的预期结果将是错误的,因为数组具有不同的值。此外 [2, 2] 和 [1, 2] 是具有不同值的数组,因此预期结果为假。此外,如果您执行compareArrays([1, 2], [2, 2]),它会返回 false,因此您的函数不是可交换的;我觉得在这样的函数中是出乎意料的。
                    【解决方案23】:

                    您似乎并不关心性能,不确定其他答案是否也如此。

                    以下是sameArrayMembers(即[1,2,2] != [1,1,2])和sameArrayMembersAsSet(即[1,2,2] == [1,1,2])的一些基准

                    没有检查 [1,1,2][1,2] 相同,如果您声称检查集合而不是长度检查,我可能应该给出。

                    const tests = {
                      'Maciej Krawczyk': (_arr1, _arr2) => {
                    
                        if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length)
                          return false;
                    
                        var arr1 = _arr1.concat().sort();
                        var arr2 = _arr2.concat().sort();
                    
                        for (var i = 0; i < arr1.length; i++) {
                    
                            if (arr1[i] !== arr2[i])
                                return false;
                    
                        }
                    
                        return true;
                      },
                      'canbax': (a1, a2) => {
                        const superSet = {};
                        for (const i of a1) {
                          const e = i + typeof i;
                          superSet[e] = 1;
                        }
                    
                        for (const i of a2) {
                          const e = i + typeof i;
                          if (!superSet[e]) {
                            return false;
                          }
                          superSet[e] = 2;
                        }
                    
                        for (let e in superSet) {
                          if (superSet[e] === 1) {
                            return false;
                          }
                        }
                    
                        return true;
                      },
                      'kennebec': (array1, array2) => {
                        return array1.slice().sort().join(',')=== array2.slice().sort().join(',');
                      },
                      'Max Heiber': function() {
                        const containsAll = (arr1, arr2) => 
                            arr2.every(arr2Item => arr1.includes(arr2Item));
                        return (arr1, arr2) => 
                            containsAll(arr1, arr2) && containsAll(arr2, arr1);
                      }(),
                      'gman': (a, b) => {
                        if (a.length !== b.length) { return false; }
                        const counts = new Map();
                        for (const v of a) {
                          const count = counts.get(v) || 0;
                          counts.set(v, count + 1);
                        }
                        for (const v of b) {
                          const count = counts.get(v);
                          if (!count) {   // undefined or 0, both mean arrays are not the same
                            return false;
                          }
                          counts.set(v, count - 1);
                        }
                        return true;
                      },
                      'Bemmu': (a, b) => {
                        if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
                          a = a.concat().sort()
                          b = b.concat().sort()
                          return a.reduce((acc,e,i) => acc && e === b[i], true)
                        } else {
                          return false;
                        }
                      },
                      'Sandeep': (array1, array2) => {
                        return JSON.stringify(array1.sort()) === JSON.stringify(array2.sort());
                      },
                      'camslice': (arr1, arr2) => {
                        const arr1test = arr1.slice().sort();
                        const arr2test = arr2.slice().sort();
                        return !arr1test.some((val, idx) => val !== arr2test[idx]);
                      },
                      'Dimitrios Stefos': (arr1, arr2) => {
                        if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length)
                            return false;
                    
                        return arr1.length==arr1.filter(word => arr2.includes(word)).length;
                      },
                      'SC1000': (arr1, arr2, opts) => {
                        function vKey(i, v) {
                          return (opts?.enforceOrder ? `${i}-` : '') + `${typeof v}-${v}`
                        }
                    
                        if (arr1.length !== arr2.length) return false;
                    
                        const d1 = {};
                        const d2 = {};  
                        for (let i = arr1.length - 1; i >= 0; i--) {
                          d1[vKey(i, arr1[i])] = true;
                          d2[vKey(i, arr2[i])] = true;
                        }
                    
                        for (let i = arr1.length - 1; i >= 0; i--) {
                          const v = vKey(i, arr1[i]);
                          if (d1[v] !== d2[v]) return false;
                        }
                    
                        for (let i = arr2.length - 1; i >= 0; i--) {
                          const v = vKey(i, arr2[i]);
                          if (d1[v] !== d2[v]) return false;
                        }
                    
                        return true
                      },
                      'Magnus Fohlström': (arr1, arr2) => {
                            let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
                            return arr1.length === arr2.length && arr1.reduce((checks, val) =>
                                checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
                       },
                    };
                    
                    // ----------------------------
                    
                    function createExposedPromise() {
                     const p = {};
                     p.promise = new Promise((resolve, reject) => {
                       p.resolve = resolve;
                       p.reject = reject;
                     });
                     return p;
                    }
                    
                    function assert(cond) {
                      if (!cond) {
                        log('assert');
                        throw new Error();
                      }
                    }
                    
                    async function main() {
                      await testResults(true, 'sameArrayMembers');
                      await testResults(false, 'sameArrayMemembersAsSet');
                      
                      async function testResults(asSet, msg) {
                        log(`\n=======[ ${msg} ] ============`);
                        const suite = new Benchmark.Suite();
                        let test;
                    
                        // reject if they fail simple test
                        const a = [1,1,2];
                        const b = [1,2,2];
                        for (const [name, fn] of Object.entries(tests)) {
                          if (fn(a, b) === asSet) {
                            log(`${name} fails for ${msg}([${a}], [${b}])`);
                          } else {    
                            suite.add(name, () => test(fn));
                          }
                        }
                    
                        let endPromise;
                    
                        suite.on('cycle', event => log(String(event.target)));
                        suite.on('complete', function() {
                          log('Fastest is ' + this.filter('fastest').map('name'));
                          endPromise.resolve();
                        });
                    
                        async function runWith(num, title) {
                          log(`------[ ${title} ] -----------`);
                    
                          const a = [];
                          for (let i = 0; i < num; ++i) {
                            a[i] = Math.random();
                          }
                          const b = [...a];
                          const c = [...a]; c[c.length / 2 | 0]++;
                    
                          endPromise = createExposedPromise();
                    
                          test = (fn) => {
                            assert(fn(a, b))
                            assert(!fn(a, c));
                          };
                    
                          suite.reset();
                          suite.run({'async': true});
                          await endPromise.promise;
                        }
                    
                        await runWith(10, 'small (10)');
                        await runWith(100, 'medium (100)');
                        await runWith(10000, 'large (10000)');
                      }
                    }
                    main();
                    
                    function log(...args) {
                      const elem = document.createElement('pre');
                      elem.textContent = args.join(' ');
                      document.body.appendChild(elem);
                    }
                    pre { margin: 0; }
                    <script src="https://unpkg.com/lodash@4.17.20/lodash.js"></script>
                    <script src="https://unpkg.com/benchmark@2.1.4/benchmark.js"></script>

                    随着 JS 引擎的更新,结果可能会随着时间而改变。以下是 2020/09/28 的一些结果

                    铬 87

                    =======[ sameArrayMembers ] ============
                    canbax fails for sameArrayMembers([1,1,2], [1,2,2])
                    Max Heiber fails for sameArrayMembers([1,1,2], [1,2,2])
                    Dimitrios Stefos fails for sameArrayMembers([1,1,2], [1,2,2])
                    SC1000 fails for sameArrayMembers([1,1,2], [1,2,2])
                    ------[ small (10) ] -----------
                    Maciej Krawczyk x 246,129 ops/sec ±0.84% (66 runs sampled)
                    kennebec x 182,234 ops/sec ±0.56% (64 runs sampled)
                    gman x 377,356 ops/sec ±1.55% (64 runs sampled)
                    Bemmu x 244,850 ops/sec ±0.76% (64 runs sampled)
                    Sandeep x 100,529 ops/sec ±1.53% (63 runs sampled)
                    camslice x 542,577 ops/sec ±0.68% (64 runs sampled)
                    Fastest is camslice
                    ------[ medium (100) ] -----------
                    Maciej Krawczyk x 12,121 ops/sec ±1.40% (63 runs sampled)
                    kennebec x 10,219 ops/sec ±1.60% (63 runs sampled)
                    gman x 41,225 ops/sec ±1.63% (62 runs sampled)
                    Bemmu x 12,400 ops/sec ±1.10% (63 runs sampled)
                    Sandeep x 12,470 ops/sec ±0.50% (64 runs sampled)
                    camslice x 57,126 ops/sec ±0.54% (64 runs sampled)
                    Fastest is camslice
                    ------[ large (10000) ] -----------
                    Maciej Krawczyk x 30.75 ops/sec ±0.86% (42 runs sampled)
                    kennebec x 27.35 ops/sec ±1.11% (38 runs sampled)
                    gman x 376 ops/sec ±0.46% (62 runs sampled)
                    Bemmu x 30.91 ops/sec ±0.77% (42 runs sampled)
                    Sandeep x 80.33 ops/sec ±0.54% (53 runs sampled)
                    camslice x 166 ops/sec ±0.44% (61 runs sampled)
                    Fastest is gman
                    
                    =======[ sameArrayMemembersAsSet ] ============
                    Maciej Krawczyk fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    kennebec fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    gman fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    Bemmu fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    Sandeep fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    camslice fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    ------[ small (10) ] -----------
                    canbax x 110,826 ops/sec ±2.07% (63 runs sampled)
                    Max Heiber x 2,699,807 ops/sec ±1.31% (63 runs sampled)
                    Dimitrios Stefos x 2,910,096 ops/sec ±0.65% (62 runs sampled)
                    SC1000 x 59,989 ops/sec ±2.61% (63 runs sampled)
                    Fastest is Dimitrios Stefos
                    ------[ medium (100) ] -----------
                    canbax x 9,624 ops/sec ±2.20% (53 runs sampled)
                    Max Heiber x 88,945 ops/sec ±0.71% (64 runs sampled)
                    Dimitrios Stefos x 94,425 ops/sec ±0.51% (65 runs sampled)
                    SC1000 x 5,742 ops/sec ±0.74% (33 runs sampled)
                    Fastest is Dimitrios Stefos
                    ------[ large (10000) ] -----------
                    canbax x 59.85 ops/sec ±1.69% (46 runs sampled)
                    Max Heiber x 13.50 ops/sec ±0.87% (26 runs sampled)
                    Dimitrios Stefos x 15.40 ops/sec ±0.89% (30 runs sampled)
                    SC1000 x 37.42 ops/sec ±1.47% (40 runs sampled)
                    Fastest is canbax
                    

                    火狐80

                    =======[ sameArrayMembers ] ============
                    canbax fails for sameArrayMembers([1,1,2], [1,2,2])
                    Max Heiber fails for sameArrayMembers([1,1,2], [1,2,2])
                    Dimitrios Stefos fails for sameArrayMembers([1,1,2], [1,2,2])
                    SC1000 fails for sameArrayMembers([1,1,2], [1,2,2])
                    ------[ small (10) ] -----------
                    Maciej Krawczyk x 118,391 ops/sec ±0.52% (65 runs sampled)
                    kennebec x 70,254 ops/sec ±0.40% (67 runs sampled)
                    gman x 201,659 ops/sec ±3.23% (57 runs sampled)
                    Bemmu x 118,133 ops/sec ±0.67% (64 runs sampled)
                    Sandeep x 69,484 ops/sec ±1.40% (65 runs sampled)
                    camslice x 130,443 ops/sec ±0.55% (65 runs sampled)
                    Fastest is gman
                    ------[ medium (100) ] -----------
                    Maciej Krawczyk x 11,418 ops/sec ±2.81% (61 runs sampled)
                    kennebec x 7,278 ops/sec ±1.37% (41 runs sampled)
                    gman x 19,748 ops/sec ±6.60% (53 runs sampled)
                    Bemmu x 11,535 ops/sec ±1.09% (62 runs sampled)
                    Sandeep x 8,234 ops/sec ±1.46% (45 runs sampled)
                    camslice x 14,277 ops/sec ±3.08% (60 runs sampled)
                    Fastest is gman
                    ------[ large (10000) ] -----------
                    Maciej Krawczyk x 65.25 ops/sec ±2.13% (49 runs sampled)
                    kennebec x 47.73 ops/sec ±0.82% (51 runs sampled)
                    gman x 210 ops/sec ±3.54% (54 runs sampled)
                    Bemmu x 66.90 ops/sec ±0.53% (50 runs sampled)
                    Sandeep x 63.13 ops/sec ±1.59% (48 runs sampled)
                    camslice x 115 ops/sec ±1.36% (56 runs sampled)
                    Fastest is gman
                    
                    =======[ sameArrayMemembersAsSet ] ============
                    Maciej Krawczyk fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    kennebec fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    gman fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    Bemmu fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    Sandeep fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    camslice fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    ------[ small (10) ] -----------
                    canbax x 79,433 ops/sec ±1.11% (57 runs sampled)
                    Max Heiber x 1,822,200 ops/sec ±0.92% (65 runs sampled)
                    Dimitrios Stefos x 2,258,820 ops/sec ±0.48% (65 runs sampled)
                    SC1000 x 35,784 ops/sec ±1.42% (63 runs sampled)
                    Fastest is Dimitrios Stefos
                    ------[ medium (100) ] -----------
                    canbax x 6,726 ops/sec ±0.60% (38 runs sampled)
                    Max Heiber x 41,620 ops/sec ±1.08% (65 runs sampled)
                    Dimitrios Stefos x 53,041 ops/sec ±1.61% (64 runs sampled)
                    SC1000 x 3,450 ops/sec ±0.56% (64 runs sampled)
                    Fastest is Dimitrios Stefos
                    ------[ large (10000) ] -----------
                    canbax x 44.18 ops/sec ±5.87% (42 runs sampled)
                    Max Heiber x 5.62 ops/sec ±4.79% (19 runs sampled)
                    Dimitrios Stefos x 6.77 ops/sec ±1.21% (21 runs sampled)
                    SC1000 x 24.18 ops/sec ±3.50% (36 runs sampled)
                    Fastest is canbax
                    

                    Safari 14

                    =======[ sameArrayMembers ] ============
                    canbax fails for sameArrayMembers([1,1,2], [1,2,2])
                    Max Heiber fails for sameArrayMembers([1,1,2], [1,2,2])
                    Dimitrios Stefos fails for sameArrayMembers([1,1,2], [1,2,2])
                    SC1000 fails for sameArrayMembers([1,1,2], [1,2,2])
                    ------[ small (10) ] -----------
                    Maciej Krawczyk x 142,798 ops/sec ±0.50% (65 runs sampled)
                    kennebec x 118,073 ops/sec ±1.12% (63 runs sampled)
                    gman x 760,109 ops/sec ±0.46% (66 runs sampled)
                    Bemmu x 136,265 ops/sec ±0.48% (63 runs sampled)
                    Sandeep x 69,868 ops/sec ±0.44% (64 runs sampled)
                    camslice x 155,548 ops/sec ±0.45% (64 runs sampled)
                    Fastest is gman
                    ------[ medium (100) ] -----------
                    Maciej Krawczyk x 8,479 ops/sec ±0.52% (46 runs sampled)
                    kennebec x 5,992 ops/sec ±2.54% (34 runs sampled)
                    gman x 83,390 ops/sec ±0.37% (64 runs sampled)
                    Bemmu x 8,615 ops/sec ±0.56% (63 runs sampled)
                    Sandeep x 5,943 ops/sec ±0.67% (64 runs sampled)
                    camslice x 8,753 ops/sec ±0.45% (47 runs sampled)
                    Fastest is gman
                    ------[ large (10000) ] -----------
                    Maciej Krawczyk x 62.66 ops/sec ±0.87% (51 runs sampled)
                    kennebec x 46.46 ops/sec ±0.66% (48 runs sampled)
                    gman x 615 ops/sec ±2.33% (60 runs sampled)
                    Bemmu x 60.98 ops/sec ±1.28% (52 runs sampled)
                    Sandeep x 49.11 ops/sec ±2.07% (47 runs sampled)
                    camslice x 66.33 ops/sec ±4.44% (50 runs sampled)
                    Fastest is gman
                    
                    =======[ sameArrayMemembersAsSet ] ============
                    Maciej Krawczyk fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    kennebec fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    gman fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    Bemmu fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    Sandeep fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    camslice fails for sameArrayMemembersAsSet([1,1,2], [1,2,2])
                    ------[ small (10) ] -----------
                    canbax x 167,041 ops/sec ±0.63% (64 runs sampled)
                    Max Heiber x 1,281,054 ops/sec ±0.74% (59 runs sampled)
                    Dimitrios Stefos x 1,127,639 ops/sec ±0.98% (64 runs sampled)
                    SC1000 x 112,824 ops/sec ±0.37% (64 runs sampled)
                    Fastest is Max Heiber
                    ------[ medium (100) ] -----------
                    canbax x 8,784 ops/sec ±0.53% (47 runs sampled)
                    Max Heiber x 37,824 ops/sec ±0.52% (65 runs sampled)
                    Dimitrios Stefos x 41,238 ops/sec ±0.85% (63 runs sampled)
                    SC1000 x 6,181 ops/sec ±0.61% (35 runs sampled)
                    Fastest is Dimitrios Stefos
                    ------[ large (10000) ] -----------
                    canbax x 63.83 ops/sec ±2.46% (49 runs sampled)
                    Max Heiber x 5.41 ops/sec ±0.52% (18 runs sampled)
                    Dimitrios Stefos x 6.02 ops/sec ±1.32% (19 runs sampled)
                    SC1000 x 42.25 ops/sec ±1.45% (45 runs sampled)
                    Fastest is canbax
                    

                    【讨论】:

                      【解决方案24】:

                      如果你只想测试原始值,你可以试试:

                      if(JSON.stringify(arr1.sort()) !== JSON.stringify(arr2.sort())) {
                        console.log('invalid');
                      }
                      

                      【讨论】:

                        【解决方案25】:

                        另一种解决方案:

                        array1.concat(array2).filter((item, index, currentArr) => currentArr.lastIndexOf(item) == currentArr.indexOf(item)).length == 0;
                        

                        [...array1, ...array2].filter((item, index, currentArr) => currentArr.lastIndexOf(item) == currentArr.indexOf(item)).length == 0;
                        

                        【讨论】:

                          【解决方案26】:

                          这是我没有排序的解决方案:

                          function isDifferent(t1,t2)
                          {
                              return ((t1.length !== t2.length) || t1.some(tag1 => !t2.some(t=>t===tag1)));
                          }
                          
                          let a1=['t','','b','xx','i','p','i'];
                          let a2=['','o','xx','b','t','p','i'];
                          
                          console.log("DIFFERENT=",isDifferent(a1,a2)); //false
                          
                          a1=['a','c','d'];
                          a2=['a','c'];
                          
                          console.log("DIFFERENT=",isDifferent(a1,a2)); //true
                          
                          a1=['a','c','d'];
                          a2=['a','c','c'];
                          
                          console.log("DIFFERENT=",isDifferent(a1,a2)); //true
                          
                          a1=['a','b','c'];
                          a2=['c','b','a'];
                          
                          console.log("DIFFERENT=",isDifferent(a1,a2)); //false

                          【讨论】:

                          • 这不起作用,例如如果 a1 = ['a','a','b'] 和 a2 = ['a', 'b', 'c']
                          【解决方案27】:
                          1. 检查两个数组是否具有相同的值但顺序可能不同

                          function compareArr(arr1, arr2) {
                            return arr1.sort().join(',') == arr2.sort().join(',');
                          }
                          
                          console.log(compareArr([1,2,3],[1,2,3])); // returns true
                          console.log(compareArr([1,2,3],[3,2,1])); // returns true
                          console.log(compareArr([1,2,3],[3,4,1])); // returns false
                          1. 检查两个数组是否具有相同的值和相同的顺序(只是不排序。)

                          function compareArrOrder(arr1, arr2) {
                            return arr1.join(',') == arr2.join(',');
                          }
                          
                          console.log(compareArrOrder([1,2,3],[1,2,3])); // returns true
                          console.log(compareArrOrder([1,2,3],[3,2,1])); // returns false
                          console.log(compareArrOrder([1,2,3],[3,4,1])); // returns false

                          【讨论】:

                            【解决方案28】:

                            代码及说明

                            function arrayEquals(arr1, arr2) {
                              // compare array lengths, if not equal then skip.
                              if (arr1.length !== arr2.length) return false;
                            
                              // setup a variable of the array length
                              let i = arr1.length;
                            
                              // iterate through every element in arr1 basically...
                              while (i--) {
                                // if arr2 doesn't include x element from arr1, return false
                                if (!arr2.includes(arr1[i])) return false;
                            
                                // passes tests and checks out
                              };
                              return true;
                            }
                            
                            // works with multiple types
                            let foo = ["foo", "bar", 1, 2, true];
                            let bar = ["bar", 2, true, "foo", 1];
                            
                            console.log(foo,bar,"Should return true: " + arrayEquals(foo, bar));
                            
                            let fob = ["bar", "foo"];
                            let oar = ["oar", "foo"];
                            
                            console.log(fob,oar,"Should return false (bar ≠ oar): " + arrayEquals(fob, oar));

                            免责声明

                            这仅支持简单类型,如字符串、数字、布尔值等。除非您编辑代码以使其递归,否则它不会真正深入您的对象或数组,但这似乎不是一个问题就回答问题本身而言。您提供了数字,所以我的答案将适用于数字。

                            【讨论】:

                              【解决方案29】:

                              这对我来说很好,但我不明白为什么有些人在数组上使用 concat 方法。

                              /**
                               * 
                               * @param {Array} firstArray 
                               * @param {Array} secondArray 
                               * @returns {boolean}
                               */
                              function arrayIsEqual(firstArray, secondArray)
                              {
                                  if (
                                      !Array.isArray(firstArray) 
                                      || !Array.isArray(secondArray) 
                                      || firstArray.length !== secondArray.length
                                  ) {
                                      console.log('Bad params!\n');
                                      return false;
                                  }
                                  $bool = firstArray === secondArray || firstArray.every((x,i)=> Array.isArray(x) ? arrayIsEqual(x, secondArray[i]) : x === secondArray[i]);
                                  console.log($bool);
                                  return $bool;
                              }
                              
                              let a = [1, 2];
                              let b = [3, 4];
                              let c = "Me and you";
                              let d = [1, [2, 3, 5], 4];
                              let e = [1, [2, 3, 5], 4];
                              let f = [1, [2, 3, 5], [4]];
                              let g = [1, [2, 3, 5], [4]];
                              
                              arrayIsEqual(a, b);
                              arrayIsEqual(b, c);
                              arrayIsEqual(c, a);
                              arrayIsEqual(a, a);
                              arrayIsEqual(d, e);
                              arrayIsEqual(e, f);
                              arrayIsEqual(e, e);
                              arrayIsEqual(g, f);
                              

                              输出

                              false
                              Bad params!
                              
                              Bad params!
                              
                              true
                              true
                              true
                              true
                              false
                              true
                              true
                              true
                              true
                              

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 2021-12-22
                                • 2014-02-03
                                • 2017-09-12
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多