【问题标题】:Using lodash to compare jagged arrays (items existence without order)使用 lodash 比较锯齿状数组(项目存在无序)
【发布时间】:2015-07-09 04:26:42
【问题描述】:

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

我有两个锯齿状数组(数组数组):

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

我想用lodash来确认上面两个锯齿数组是一样的。 “相同”是指array1 中没有不包含在array2 中的项目。请注意,锯齿状数组中的项目实际上是数组。所以我想在内部数组之间进行比较。

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

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

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

这两种方法都有效,因为字母总是按顺序排列的。


更新:最初的问题是关于“数组”(而不是锯齿状数组),多年来,许多人讨论(并添加了答案)关于比较简单的一维数组(没有注意到问题中提供的示例实际上与他们期望的简单一维数组并不相似)。

【问题讨论】:

    标签: javascript arrays lodash jagged-arrays


    【解决方案1】:

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

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

    请注意,.sort() 将改变数组。如果这对您来说有问题,请先使用(例如).slice() 或扩展运算符 (...) 进行复制。

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

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

    Lodash 的 sortBy() 不会改变数组。

    【讨论】:

    • 考虑到 array.sort() 正在改变原始数组。也许这个可能更好: var array1 = [['a', 'b'], ['b', 'c']]; var array2 = [['b', 'c'], ['a', 'b']]; _.isEqual([...array1].sort(), [...array2].sort()); //真
    • 添加了两句话,指出 .sort() 发生了变异,并建议在用户遇到问题时首先复制的选项。
    • 如果你已经在使用 lodash,你可以通过 _.isEqual(_.sortBy(array1), _sortBy(array2)) 来防止突变。
    • @DanielBudick 谢谢!我已将其添加到答案中。很好的建议。
    【解决方案2】:

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

    您可以为此使用 flatten() 和 difference(),如果您不关心 array2 中是否有项目 array1 中,这将非常有效。听起来你在问 array1 是 array2 的子集吗?

    var array1 = [['a', 'b'], ['b', 'c']];
    var array2 = [['b', 'c'], ['a', 'b']];
    
    function isSubset(source, target) {
        return !_.difference(_.flatten(source), _.flatten(target)).length;
    }
    
    isSubset(array1, array2); // → true
    array1.push('d');
    isSubset(array1, array2); // → false
    isSubset(array2, array1); // → true
    

    【讨论】:

      【解决方案3】:

      我们可以使用_.difference函数看看有没有区别。

      function isSame(arrayOne, arrayTwo) {
         var a = _.uniq(arrayOne),
         b = _.uniq(arrayTwo);
         return a.length === b.length && 
                _.isEmpty(_.difference(b.sort(), a.sort()));
      }
      
      // examples
      console.log(isSame([1, 2, 3], [1, 2, 3])); // true
      console.log(isSame([1, 2, 4], [1, 2, 3])); // false
      console.log(isSame([1, 2], [2, 3, 1])); // false
      console.log(isSame([2, 3, 1], [1, 2])); // false
      
      // Test cases pointed by Mariano Desanze, Thanks.
      console.log(isSame([1, 2, 3], [1, 2, 2])); // false
      console.log(isSame([1, 2, 2], [1, 2, 2])); // true
      console.log(isSame([1, 2, 2], [1, 2, 3])); // false
      

      希望对你有所帮助。

      StackBlitz添加示例链接

      【讨论】:

      • 错了,你的函数将得到true for console.log(isSame([1,2], [2,3,1]));
      • 感谢@DavidLin 指出。我已经做出改变以考虑这种情况。谢谢您,给您带来的不便,我们深表歉意。
      • 如果长度不同,您不需要为 a 和 b 切换位置。如果长度不同,那么它们就不可能相同了,所以 if(arrayOne.lenght !== arrayTwo.lenght) return false;
      • -1 没有那些 ab 变量。您if-then 部分中使用这些变量,您要做的第一件事就是丢弃在第 2 行加载的那些值。我认为以下单行将完全相同:return arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort()); .而<=也可以改进为===
      • _.difference 将返回第一个参数的缺失项,但不会返回第二个参数中的缺失项。因此,当您在 1 日和 2 日重复项目时,这将错误地返回 trueisSame([1, 2, 3], [1, 2, 2])
      【解决方案4】:

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

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

      var array1 = [['a', 'b'], ['b', 'c']];
      var array2 = [['b', 'c'], ['b', 'a']];
      
      var r = array1.map(x=>x.sort()).sort().join() === array2.map(x=>x.sort()).sort().join();
      
      console.log(r);

      【讨论】:

        【解决方案5】:

        您可以为此使用 lodashs xor

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

        如果您认为数组 [1, 1] 与数组 [1] 不同,那么您可能会像这样提高性能:

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

        【讨论】:

        • 数组无论如何都需要排序。
        • 这应该是较新版本的更好方法
        • @Sovattha Sok 数组不需要排序。做_.xor([3,4], [4,3]).length == 0会让你变得真实。
        • 提醒一句:这种技术适用于“小”数组,但如果您的数组很大并且大部分不同,因为 _.xor() 会保持超越第一个差异。换句话说,它不会在检测到第一个差异时快速返回。
        • xor 比排序数组解决方案慢 60-80%(取决于浏览器和机器)。性能对比:jsbench.me/drksdwsbgk/1
        【解决方案6】:

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

        // Does array a contain elements of array b?
        const union = new Set([...a, ...b]);
        const contains = (a, b) => union.size === a.length && union.size === b.length;
        // Since order is not important, just data validity.
        const isEqualSet = (a, b) => union.contains(a, b) || union.contains(b, a)
        

        contains() 的基本原理是,如果a 确实包含b 的所有元素,那么将它们放在同一个集合中不会改变大小。

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

        从那里,为了更简洁,我们可以将其归结为以下内容:

        const isEqualSet = (a: string[], b: sting[]): boolean => {
          const union = new Set([...a, ...b])
          return union.size === a.length && union.size === b.length;
        }
        

        编辑:这不适用于 obj[{a: true}, true, 3] 但可能会比较数组内容,只要它们是原始元素。方法修复并针对使用不同顺序的相同值的两个数组进行测试。不适用于对象类型。我建议制作一个通用助手,它根据需要比较的类型调用助手函数。从非常棒的 lodash 库中尝试 _.isEqual(a. b);

        【讨论】:

        • 我真的很喜欢这种方法,但是当ab 的每个重复元素在它们之间不一样时,它是否有效?比如 a = [ 1, 1, 2, 3] 和 b = [1, 2, 2, 3]
        • 好的,我进行了快速测试,但没有,请小心
        【解决方案7】:

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

        这是一个老问题,但我在使用 .sort()sortBy() 时遇到了问题,所以我改用了这个:

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

        它旨在快速失败,并且对于我的目的来说工作正常。

        【讨论】:

        • 最后一次检查真的有必要吗? array1.every((str) => array2.includes(str)) 应该足够了。此外,OP 想要使用 lodash,您至少应该说明为什么要提出 vanillaJS 解决方案(......现在我们拥有了所有并包含......)。还请提供一个示例,如何将您的函数应用于所提供的问题(二维数组)。
        • 这是一个很好的观点 - 我没有解决它的多维方面,而不是对 lodash 的要求。我认为任何人(像我一样)搜索 lodash methods to compare arrays without considering order 以查看现代 Javascript 中的替代方案会很有用。第二次检查是必要的,否则arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3']) 将返回 true。我会把它留在这里,因为它可能会有所帮助,但我很感激我没有回答这个问题
        【解决方案8】:

        我确实觉得发布这个解决方案很不干净,但是:

        var array1 = [['a', 'b'], ['b', 'c']];
        var array2 = [['b', 'c'], ['a', 'b']];
        _.isMatch([array1], [array2]) && _.isMatch([array2], [array1]) // true
        
        array1 = [['b', 'a'], ['c', 'b']];
        array2 = [['b', 'c'], ['a', 'b']];
        _.isMatch([array1], [array2]) && _.isMatch([array2], [array1]) // also true
        

        请注意,您必须array1array2 包装到容器(数组、对象)中才能使其正常工作?为什么?这可能有一个非常愚蠢的原因。

        【讨论】:

          【解决方案9】:
          import { differenceBy } from 'lodash'
          
          export default function (arr1, arr2) {
              return !differenceBy(arr1, arr2).length && arr1.length === arr2.length
          }
          

          如果没有不同的字符且数组长度相同,则使它们相同。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多