Javascript - 检查数组中的数组是否相同

Javascript - Check if arrays within an array are the same

提问人:Philipp M 提问时间:6/20/2023 最后编辑:M. JustinPhilipp M 更新时间:10/29/2023 访问量:156

问:

在我的情况下,检查数组中的数组是否相同的最佳方法是什么?

var arrSession = [
  {
    type: '1',
    usecase: [ '1' ]
  },
  {
    type: '1',
    usecase: [ '1' ]
  }
];

var checkUsecase = arrSession.every(isSame);

function isSame(obj, index, arr) {
    if (index === 0) {
        return true;
    } else {
        return (
            (obj.type === arr[index - 1].type) &&
            (obj.usecase === arr[index - 1].usecase)
        );
    }
}

console.log('checkUsecase:');
console.log(checkUsecase);

数组中的“用例”对象使用字符串“”,而 isSame 函数用于工作。但现在它们也是数组。如何更改isSame功能?

这是一把小提琴:https://jsfiddle.net/3j0odpec/

JavaScript 数组 数据结构 比较 相等

评论

0赞 Liftoff 6/20/2023
这个问题值得一读。不幸的是,在 Javascript 中比较数组并不是最容易的事情。
0赞 trincot 6/20/2023
用于数组元素的数据类型是什么?总是串?或者更多的对象、数组、集合、映射、日期,...等?usecase
0赞 Peter Seliger 6/26/2023
@PhilippM......关于所有提供的答案,还有什么问题吗?
0赞 Philipp M 6/27/2023
@PeterSeliger 不,这太完美了!:-) ...两个答案都很棒,很难决定接受哪个。非常感谢您的帮助,非常感谢!

答:

4赞 Alexander Nenashev 6/20/2023 #1

首先,我们制作一些递归比较函数来遍历嵌套数组/对象。然后我们在数组上运行它,比较当前项目是否等于前一个项目。

这绝对比比较 OP 数据的 JSON.stringized 数组项更快:

enter image description here

const arrSession = [
    {
        type: '1',
        usecase: ['1']
    },
    {
        type: '1',
        usecase: ['1']
    }
];

const isSameItems = arrSession.every((item, idx, arr) => idx === 0 || isSame(item, arr[idx - 1]));

console.log('the array has all items the same: ', isSameItems);

function isSame(a, b) {

    const iterator = Array.isArray(a) && Array.isArray(b) ? a.keys() : 
    (typeof a === 'object') && (typeof b === 'object') ? Object.keys(a) : null;

    if (iterator) {
        for (const i of iterator) {
            if (!isSame(a[i], b[i])) {
                return false;
            }
        }
        return true;
    }
    
    return a === b;

}

<script benchmark data-count="1">

    const arrSession = JSON.parse(JSON.stringify(Array.from({ length: 300000 }).reduce(arr => arr.push(...[
        {
            type: '1',
            usecase: ['1'],
            child: {
                type: '1',
                usecase: ['1'],
                child: {
                    type: '1',
                    usecase: ['1'],
                    child: {
                        type: '1',
                        usecase: ['1'],
                    }
                }
            },
            child: {
                type: '1',
                usecase: ['1'],
            }
        }
    ]) && arr, [])));

    // @benchmark JSON.stringify

    arrSession.every((item, idx, arr) => idx === 0 || JSON.stringify(item) === JSON.stringify(arr[idx - 1]));

    // @benchmark recursive isSame

    function isSame(a, b) {

        const iterator = Array.isArray(a) && Array.isArray(b) ? a.keys() : 
        (typeof a === 'object') && (typeof b === 'object') ? Object.keys(a) : null;

        if (iterator) {
            for (const i of iterator) {
                if (!isSame(a[i], b[i])) {
                    return false;
                }
            }
            return true;
        }

        return a === b;

    }

    // @run 
    
    arrSession.every((item, idx, arr) => idx === 0 || isSame(item, arr[idx - 1]));
    
</script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>

评论

0赞 trincot 6/20/2023
不鼓励使用 -- 参见 MDN 页面上的多个通知。__proto__
0赞 Philipp M 6/27/2023
也是一个很好的答案,感谢您的帮助!非常感谢!很难决定接受哪个答案!
3赞 Peter Seliger 6/20/2023 #2

这个答案也选择了已经提出的一些基于比较的方法......

const isFullItemEquality = arrSession
  .every((item, idx, arr) =>
    idx === 0 || isDeepDataStructureEquality(item, arr[idx - 1])
  );

...只是它不利用.JSON.stringify

对于性能也很重要的 JSON 符合数据结构的相同性/相等性比较,可以考虑使用以下 isDeepDataStructureEquality 的递归实现......

<script>
  // implemented by Peter Seliger
  function isDeepDataStructureEquality(a, b) {
    let isEqual = Object.is(a, b);

    if (!isEqual) {
      if (Array.isArray(a) && Array.isArray(b)) {

        isEqual = (a.length === b.length) && a.every(
          (item, idx) => isDeepDataStructureEquality(item, b[idx])
        );
      } else if (
        a && b
        && (typeof a === 'object')
        && (typeof b === 'object')
      ) {
        const aKeys = Object.keys(a);
        const bKeys = Object.keys(b);

        isEqual = (aKeys.length === bKeys.length) && aKeys.every(
          (key, idx) => isDeepDataStructureEquality(a[key], b[key])
        );
      }
    }
    return isEqual;
  }
</script>
<script>
  // implemented by Alexander Nenashev
  function isSame(a, b) {

    const iterator = Array.isArray(a) && Array.isArray(b) ? a.keys() : 
    (typeof a === 'object') && (typeof b === 'object') ? Object.keys(a) : null;

    if (iterator) {
        for (const i of iterator) {
            if (!isSame(a[i], b[i])) {
                return false;
            }
        }
        return true;
    }

    return a === b;

  }
</script>
<script benchmark data-count="10">

  const arrSession = JSON.parse(JSON.stringify(Array
    .from({ length: 300000 })
    .reduce(arr => arr.push(...[{
      type: '1',
      usecase: ['1'],
      child: {
        type: '1',
        usecase: ['1'],
        child: {
          type: '1',
          usecase: ['1'],
          child: {
            type: '1',
            usecase: ['1'],
          },
        },
      },
      child: {
        type: '1',
        usecase: ['1'],
      }
    }]) && arr, [])));

    // countercheck implementations with an unequal data structure.
    // arrSession.at(-1).child.usecase[0] = 0;

    // @benchmark JSON.stringify
    arrSession.every((item, idx, arr) =>
      idx === 0 || JSON.stringify(item) === JSON.stringify(arr[idx - 1])
    );
    // @benchmark recursive isSame
    arrSession.every((item, idx, arr) =>
      idx === 0 || isSame(item, arr[idx - 1])
    );
    // @benchmark recursive isDeepDataStructureEquality
    arrSession.every((item, idx, arr) =>
      idx === 0 || isDeepDataStructureEquality(item, arr[idx - 1])
    );
</script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>

评论

0赞 trincot 6/20/2023
不鼓励使用 -- 参见 MDN 页面上的多个通知。__proto__
0赞 Alexander Nenashev 6/20/2023
@PeterSeliger我的坏处是快点。我确实看到,使用仅处理 2 个值 A 和 B 并不是最佳选择,使用与以前相同的逻辑更改它,只是避免了 .所以现在我的函数在速度方面更能与你的函数相媲美。我想你并不反对在你的答案中修复我的代码。这是 StackOverflow 的一些缺点,如果你不够快,即使你的答案是最好的,你也不会得到任何分数......reduce()reduce()
0赞 Alexander Nenashev 6/20/2023
@PeterSeliger比较数组和对象键长度是明智之举。我之前在我的代码中做了同样的事情,但今天忘记添加这个检查