记录–如何判断两个数组的内容是否相等

  • 记录–如何判断两个数组的内容是否相等已关闭评论
  • 89 次浏览
  • A+
所属分类:Web前端
摘要

给定两个数组,判断两数组内容是否相等。例:思考几秒:有了??Arrary.prototype.indexOf() 是使用的严格相等算法 => NaN值永远不相等


这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--如何判断两个数组的内容是否相等

题目

给定两个数组,判断两数组内容是否相等。

  • 不使用排序
  • 不考虑元素位置

例:

[1, 2, 3] 和 [1, 3, 2] // true [1, 2, 3] 和 [1, 2, 4] // false

思考几秒:有了??

1. 直接遍历✍

  • 直接遍历第一个数组,并判断是否存在于在第二个数组中
  • 求差集, 如果差集数组有长度,也说明两数组不等(个人感觉比上面的麻烦就不举例了)
const arr1 =  ["apple", "banana", 1] const arr2 =  ["apple", 1, "banana"]  function fn(arr1, arr2) {   // Arrary.some: 有一项不满足 返回false   // Arrary.indexOf: 查到返回下标,查不到返回 -1   if (arr1.length !== arr2.length) {     return false;   }   return !arr1.some(item => arr2.indexOf(item)===-1) }  fn(arr1,arr2) // true

  • 细心的小伙伴就会发现:NaN 会有问题
const arr1 =  ["apple", "banana", NaN] const arr2 =  ["apple", NaN, "banana"]  function fn(arr1, arr2) {   if (arr1.length !== arr2.length) {     return false;   }   return !arr1.some(item => arr2.indexOf(item)===-1) }  fn(arr1,arr2) // false

Arrary.prototype.indexOf() 是使用的严格相等算法 => NaN值永远不相等

Array.prototype.includes() 是使用的零值相等算法 => NaN值视作相等

  • 严格相等算法: 与 === 运算符使用的算法相同
  • 零值相等不作为 JavaScript API 公开, -0和0 视作相等,NaN值视作相等,具体参考mdn文档:

记录--如何判断两个数组的内容是否相等

  • 使用includes
const arr1 =  ["apple", "banana", NaN] const arr2 =  ["apple", NaN, "banana"]  function fn(arr1, arr2) {   if (arr1.length !== arr2.length) {     return false;   }   return !arr1.some(item => !arr2.includes(item)) }  fn(arr1,arr2) // true

使用includes 确实可以判断NaN了,如果数组元素有重复呢?

// 重复的元素都是banana const array1 = ["apple", "banana", "cherry", "banana"]; const array2 = ["banana", "apple", "banana", "cherry"]; // 或者 // 一个重复的元素是banana, 一个是apple const array1 = ["apple", "banana", "cherry", "banana"]; const array2 = ["banana", "apple", "apple", "cherry"];

由上可知:这种行不通,接下来看看是否能从给数组元素添加标识入手

2. 把重复元素标识编号✍

这个简单:数组 元素重复 转换成val1, val2

function areArraysContentEqual(arr1, arr2) {   if (arr1.length !== arr2.length) {     return false;   }    // 重复数组元素 加1、2、3   const countArr1 = updateArray(arr1)   const countArr2 = updateArray(arr2)    /**    *     * @param {*} arr 数组 元素重复 转换成val1, val2    * @returns     */   function updateArray(arr) {     const countMap = new Map();     const updatedArr = [];      for (const item of arr) {       if (!countMap.has(item)) {         // 如果元素是第一次出现,直接添加到结果数组         countMap.set(item, 0);         updatedArr.push(item);       } else {         // 如果元素已经出现过,添加带有编号的新元素到结果数组         const count = countMap.get(item) + 1;         countMap.set(item, count);         updatedArr.push(`${item}${count}`);       }     }     return updatedArr;   }   const flag = countArr1.some(item => !countArr2.includes(item))   return !flag }  const array1 = ["apple", "banana", "cherry", "banana"]; const array2 = ["banana", "apple", "banana", "cherry"];  areArraysContentEqual(array1, array2) // true  // 其实这种存在漏洞的 const array3 = ["apple", "banana", "cherry", "banana", 1, '1', '1' ]; const array4 = ["banana", "apple", "banana", "cherry", '1', 1, 1]; // 应该是false areArraysContentEqual(array3, array4) // true

因为把判断的 转为了字符串 updatedArr.push(${item}${count}) 所以出问题了

3. 统计元素次数(最终方案)✍

function areArraysContentEqual(arr1, arr2) {   if (arr1.length !== arr2.length) {     return false;   }    // 创建计数对象,用于记录每个元素在数组中的出现次数   const countMap1 = count(arr1)   const countMap2 = count(arr2)    // 统计数组中的元素出现次数   function count(arr = []) {     const resMap = new Map();     for (const item of arr) {       resMap.set(item, (resMap.get(item) || 0) + 1);     }     return resMap   }   // 检查计数对象是否相等   for (const [key, count] of countMap1) {     if (countMap2.get(key) !== count) {       return false;     }   }    return true; }  const array1 = ["apple", "banana", "cherry", "banana", 1, '1', '11', 11]; const array2 = ["banana", "apple", "banana", "cherry", '1', 1, '11', 11];  areArraysContentEqual(array1, array2) // true

4. 评论区大佬方案(+1、-1)?

  1. 只需要一个对象
  2. 遍历第一个数组就 +1
  3. 遍历第二个数组就 - 1
  4. 最后遍历对象,只要不是都是 0 就等于不匹配

这样就不需要俩个对象了,而且第二个遍历的时候如果找不到这个值的话也可以直接退出了

 

function areArraysContentEqual3(arr1, arr2) {   if (arr1.length !== arr2.length) {     return false;   }    const countMap = new Map();    // 计数第一个数组的元素   for (const item of arr1) {     countMap.set(item, (countMap.get(item) || 0) + 1);   }    // 比较第二个数组与计数   for (const item of arr2) {     const val = countMap.get(item);     if (val === undefined || val <= 0) {       return false;     }     countMap.set(item, val - 1);   }    return true; }

5. 评论区大佬方案(操作第二个数组)?

遍历第一个数组,在第二个数组找到就删除第二个数组中对应的元素,没有找到直接不等,最后再判断一下第二个数组的长度即可。实际使用中一般不直接操作原数组,浅复制一下就好

可能没有前几个性能好,但是想法还是很好的点赞~

function areArraysContentEqual2(arr1=[], arr2=[]) {   arr2 = [...arr2]   if (arr1.length !== arr2.length) {     return false;   }    arr1.some(item => {     // 找到元素在第二个数组中的位置     const index = arr2.findIndex(item1 => {       if (isNaN(item) && isNaN(item1)) {         return true       }       return item ===item1     })     if (index !== -1 ) {       arr2.splice(index, 1)     }   })   return !arr2.length }

注意事项

这个题需要注意:

  • 先判断长度,长度不等 必然不等
  • 元素可重复
  • 边界情况考虑
    • '1' 和 1 (Object的key是字符串, Map的key没有限制)
    • NaN
    • null undefined

本文转载于:

https://juejin.cn/post/7290786959441117243

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--如何判断两个数组的内容是否相等