如何在Javascript中获取嵌套数组的长度?

5

我有一个嵌套数组的例子:

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];

这是获取嵌套数组长度的函数:

Array.prototype.getLength = function() {
  var sum = 0;
  function getMultiLength(array) {
    for (count = 0; count < array.length; count ++) {
      sum ++;
      if (!array[count].length) {
        getMultiLength(array[count]);
      }
    }
  }
  getMultiLength(this.valueOf());
  return sum;
};

我期望得到的结果是12,但实际上我却陷入了无限循环:

testArray.getLength(); //infinite loop

有人知道为什么以及如何获取嵌套数组的长度吗?

9个回答

10

您的代码存在问题

您现有的代码失败是因为递归检查的顺序错误。如果长度 不为零,则需要递归。所以应该是:

  if (array[count].length) getMultiLength(array[count]);
  else sum++;

您的代码中,即使array[count]不是数组(因为如果array[count]不是数组,则length将未定义),getMultiLength也会被调用。因此,它将一直递归下去。通过在调试器中逐步执行代码,这将很容易发现。
顺便说一下,在这种情况下,您不需要this.valueOf()。这与this相同。
调整您的代码
但实际上,您可以通过消除不必要的内部函数并使用递归调用的返回值来简化代码:
Array.prototype.getLength = function() {
  let sum = 0;
  for (let count = 0; count < this.length; count ++) {
    sum += this[count].length ? this[count].getLength() : 1;
  }
  return sum;
};

有些人可能更喜欢使用“reduce”来编写这个代码块:
Array.prototype.getLength = function() {
  return this.reduce((sum, elt) => 
    sum + (elt.length ? elt.getLength() : 1), 0);
};

使用扁平化的另一种解决方案

另一种解决方案是将数组扁平化,然后找到扁平化数组的长度。这里我们使用一个生成器来创建一个扁平化器,它非常容易阅读和理解(ES6特性):

function *flatten(array) {
  for (elt of array) 
    if (Array.isArray(elt)) yield *flatten(elt);
    else yield elt;
}

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];

console.log(Array.from(flatten(testArray)).length);

flatten的替代实现

或者,使用您自己喜欢的flatten实现,例如这个递归版本:

function flatten(value) {
  return Array.isArray(value) ? [].concat(...value.map(flatten)) ? value;
}

或者在ES5中
function flatten(value) {
  return Object.prototype.toString.call(value) === '[object Array]' ?
    [].concat.apply([], value.map(flatten)) :
    value;
}

将其放在Array原型上

如果您坚持要将其放在原型上,则

Object.defineProperty(Array.prototype, 'getLength', {
  value() { return flatten(this).length; }
});

使用defineProperty使该属性不可枚举,不可配置等。

2

以上所有答案都很有帮助,我只是想再添加一个简单的答案。希望它对未来的某个人有用。

const getLength = arr => arr.flat(Infinity).length;

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];
console.log(getLength(testArray));

我们在这里使用flat()方法将数组展平为单个数组,然后计算其长度。请注意,我们已将深度传递为Infinity,因为我们想要深入到底并计算整个长度。

flat()方法创建一个新的数组,其中所有子数组元素都被递归地连接到该数组中,直到达到指定的深度。在我们的情况下,我们将定义深度为Infinity。

了解更多关于flat()的信息。


0

有一个递归调用嵌套数组来计算它们的非数组项:

var testArray = [1, 2, [3, 4, [5, 6], 7], 8, 9, [10, 11], 12];

Array.prototype.getLength = function () {
    function getMultiLength(array) {
        var sum = 0;
        for (var count = 0; count < array.length; count++) {
            if (Array.isArray(array[count])) {
                sum += getMultiLength(array[count]);
            } else {
                sum++;
            }
        }
        return sum;
    }

    return getMultiLength(this.valueOf());
};

alert(testArray.getLength());


0

我想贡献的两种方法:

递归:

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];
         flat = a => a.reduce((p,c) => p.concat(Array.isArray(c) ? flat(c) : c),[]);
       result = flat(testArray).length;
console.log(result);

游击战:

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];
       result = JSON.stringify(testArray).match(/,/g).length+1;
console.log(result);


0

试试这个:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];
var s = 1;
$.each(testArray, function(index, value){
    s = s + $(this).length; 
});
console.log(s);

2
答案不应依赖于未在问题中标记或代码中指示的库。至少应该解释所需的库。 - RobG
没有必要仅为 each 引入 jQuery - 使用 ES6 方法并指向一个 polyfill。 - Jeremy J Starcher
@JeremyJStarcher 我同意,但你指的是哪个ES6方法? - user663031
@torazaburo - https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach - Jeremy J Starcher

0

我使用递归调用来查找嵌套数组的长度

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];

var totalLen=0;
function length(arr){

   for(var ele in arr){
     if(Array.isArray(arr[ele])){
       length(arr[ele])
     }else{
         totalLen++;
     }
   }

}

length(testArray);
console.log(totalLen); //o/p 12

这里没有使用全局变量的即兴编程

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];


var ArrayUtils=function(){

      var totalLength=0;

      function getNestedArrayLength(arr){

         for(var ele in arr){

             if(Array.isArray(arr[ele])){
               getNestedArrayLength(arr[ele])
             }else{
                 totalLength++;
             }
           }
      }

      function getLength(arr){

            getNestedArrayLength(arr);
            return totalLength;

      }

      return {
          getLength:getLength
      }
}

var aU=new ArrayUtils();
var length=aU.getLength(testArray);

console.log(length); //Op 12

你能否尝试以不使用全局变量的方式编写此代码,并将长度作为函数值返回? - user663031
@torazaburo,你能检查一下吗?我尝试了上面的代码,没有使用全局变量。 - Saravana

0

你好,这里的答案使用Array.isArray来识别它是否为数组,然后再次调用函数来执行相同的操作,以此类推。

let test = [1, [2, [3, [4, [5, 6],7,[8,9,10,[11,12]]]]]];
let length = 0;
function len(array){
   for(let i in array){
      if(Array.isArray(array[i])){
          len(array[i])
       }else{
          length++
       }
    }
    return length;
};

len(test)
console.log(length)

0

这个不适用于[].concat.apply([[]],[[1],[2]]).length - penduDev
一个不同的问题 - rearThing
我后来意识到,稍微编辑一下你的答案就给了我解决我在上面评论中提到的问题的方法,即[].concat.apply([], testArray).length - penduDev

-1

试试这个:

Array.prototype.getLength = function() {
  var sum = 0;
  function getMultiLength(array) {
    for (var count = 0; count < array.length; count ++) {
      sum ++;
      if (array[count].length) {
        getMultiLength(array[count]);
      }
    }
  }
  getMultiLength(this.valueOf());
  return sum;
};

var testArray = [1,2,[3,4,[5,6],7],8,9,[10,11],12];

testArray.getLength()
  1. 不要使用全局变量count。
  2. 如果数组为空,为什么要计算它的数量?

答案应解释OP的问题以及如何解决它。仅有代码的答案并不特别有帮助。您尝试过使用元素为字符串的数组吗? - RobG
不要直接给出答案,好吗?请查看答案下面提到的要点。 - Drag13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接