【问题标题】:include() method for nested arrays嵌套数组的 include() 方法
【发布时间】:2019-02-09 09:12:39
【问题描述】:

我正在努力检查数组中的数组。 include() 方法似乎不是为它设计的,因为在这种情况下它总是返回 false。下面是与indexOf 相同的场景示例。也许我需要的只是语法帮助,欢迎任何想法。

arr = [1,[9,9],3,4,5];

if (arr.indexOf(el) !== -1) {
   console.log(`the array contains ${el}`);
} else {
   console.log(`doesn't contain ${el}`);
}

当然,上面的返回 true 代表 1、3、4、5 和 false 代表 2。现在问题来了。我正在尝试使用[9,9] 之类的数组来提供此方法,以查看是否已经存在。

let el = [9,9];
// console: "doesn't contain 9,9"

另一方面,下面是可以的,这让我认为这只是一个语法问题(?)

let el = arr[1];
// console: "the array contains 9,9"

我通过编写带有for 循环的检查器函数找到了一种解决方法,但是随着您添加要求,这很快变得庞大。我很想知道一种更聪明的方法。

谢谢。

【问题讨论】:

  • 我已经更新了我的答案以添加一个不使用 JSON.stringify() 的简洁实现,以使其更完整。

标签: javascript arrays


【解决方案1】:

您遇到的问题是数组是引用类型。因此,只有当两个数组引用相同的底层数组时,比较两个数组才会返回 true,而对于不同的数组,即使它们具有相同的值,也会返回 false。

const arr1 = [1, 2];
const arr2 = [1, 2];
const arr3 = arr1;

console.log(arr1 === arr3);
console.log(arr1 !== arr2);

要解决您的问题,您的include 函数需要按值比较(深度比较),您只需使用JSON.stringify() 即可。

此方法速度快但有限,适用于内部没有方法和 DOM 节点的简单 JSON 样式对象

请参阅SO post,了解 JavaScript 中的对象比较。

这是一个工作示例:

function include(arr, value) {
  const stringifiedValue = JSON.stringify(value);
  for (const val of arr) {
    if (JSON.stringify(val) === stringifiedValue) {
      return true;
    }
  }
  return false;
}

console.log(include([1, 2, 3, 4], 3));
console.log(include([1, 2, 3, [1, 2]], [1, 2]));
console.log(include([1, 2, 3, [1, 2]], [1, 2, 3]));

这是在没有JSON.stringify() 的情况下进行深度比较的另一种方法,它适用于内部数组和标量值:

function include(arr, value) {
  const valArity = Array.isArray(value) ? value.length : 1;
  for (let item of arr) {
    if (valArity > 1 && Array.isArray(item) && item.length === valArity) {
      if (item.every((val, i) => val === value[i])) {
        return true;
      }
    } else if (item === value) {
      return true;
    }
  }
  return false;
}

console.log(include([1, 2, 3, 4], 3));
console.log(include([1, 2, 3, [1, 2]], [1, 2]));
console.log(include([1, 2, 3, [1, 2]], [1, 2, 3]));
console.log(include([1, 2, 'abc', 4], 'abc'));

这是一个修改后的版本,适用于简单的具有标量属性、数组和标量的对象

function include(arr, value) {
  const valArity = Array.isArray(value) ? value.length : 1;
  const isObject = value instanceof Object;
  for (let item of arr) {
    if (valArity > 1 && Array.isArray(item) && item.length === valArity) {
      if (item.every((val, i) => val === value[i])) {
        return true;
      }
    } else if (isObject && item instanceof Object && item) {
      const numEntries = Object.keys(value).length;
      const entries = Object.entries(item);
      if (numEntries === entries.length) {
        if (entries.every(([k, v]) => value[k] === v)) {
          return true;
        }
      }
    } else if (item === value) {
      return true;
    }
  }
  return false;
}

console.log(include([1, 2, 3, 4], 3));
console.log(include([1, 2, 3, [1, 2]], [1, 2]));
console.log(include([1, 2, 3, [1, 2]], [1, 2, 3]));
console.log(include([1, 2, { a: 1 }, 4], { a: 1 }));
console.log(include([1, 2, { a: 1, b: 2 }, 4], { a: 1 }));
console.log(include([1, 2, 'abc', 4], 'abc'));

【讨论】:

  • 虽然字符串化每个属性确实会产生一定程度的处理,但字符串化算法与递归检查这些值的方法非常相似,这也是事实。这个答案也许还可以使用一个小的解释来解释为什么将具有相同值的两个不同数组相互比较会导致错误。
  • 缓存value 字符串而不是在每次迭代中计算它也可能有意义。以防万一将来有人出现并将其用作解决方案。
【解决方案2】:

这里我们可以使用Array.prototype.some()来做到这一点

注意我们添加了一个辅助方法来检查每个元素,我没有费心编写对象检查,但你明白了。

调整为支持子数组

let arr = [1, [9, 9], 3, 4, 5];
let el = [9, 9];

let arr2 = [1, [1,[9, 9]], 3, 4, 5];
let el2 = [1,[9, 9]];

const someCheck = (item, compare) => {
  if(typeof item !== typeof compare) return false;
  if(typeof item === 'string') return item === compare;
  if(typeof item === 'number') return item === compare;
  if(Array.isArray(item)) {
    console.log('checking array');
    return item.reduce((accum, o, i) => accum && (someCheck(o,compare[i])));
  }
  // no plain object support yet.
  return false;
}


if (arr.some(e => someCheck(e, el))) {
  console.log(`the array contains ${el}`);
} else {
  console.log(`doesn't contain ${el}`);
}

if (arr2.some(e => someCheck(e, el2))) {
  console.log(`the array contains ${el2}`);
} else {
  console.log(`doesn't contain ${el2}`);
}

【讨论】:

  • 还有[9, [9, 9]]? ;D
  • o === compare[i] 需要递归到 someCheck 中。
  • 现在支持子数组。
【解决方案3】:

您需要遍历数组并检查每个元素是否为数组,然后检查每个索引。像这样的:

let arr = [1,[9,9],3,4,5];
let el = [9,9];
let contains = true;

for (var i = 0; i < arr.length; i++) {
  if (Array.isArray(arr[i])) {
    var equals = true
    if(arr[i].length !== el.length)
        equals = false;
    for(var j = arr[i].length; j--;) {
        if(arr[i][j] !== el[j])
           equals = false;
    }  
    if (equals) {    
      contains = true;
      break;
    }
  } else {
    if (arr.indexOf(el) !== -1){
        contains = true;        
        break;
      }
    else{contains = false;}
  }
}

if (contains) {
  console.log(`the array contains ${el}`);
} else {
  console.log(`doesn't contain ${el}`)
}




  

【讨论】:

    猜你喜欢
    • 2012-02-05
    • 1970-01-01
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2018-02-04
    • 2022-01-17
    • 2020-05-17
    相关资源
    最近更新 更多