嵌套列表的Javascript长度

时间:2018-04-24 12:25:42

标签: javascript arrays

目标:给定一组混合类型可确定每个级别的元素数量。如果同一级别有两个子阵列,则每个子元素都会计入该级别的元素总数。

方法

Array.prototype.elementsAtLevels = function( level, levelData ) {
  if ( level == undefined ) { level = 0;  } else { level += 1 }
  if ( levelData == undefined ) { levelData = {}; }
  if ( levelData[level] == undefined ) { levelData[level] = this.length} else { levelData[level] += this.length }
  this.map(function(e, i) {if (Array.isArray(e)){ e.elementsAtLevels(level, levelData) }})
  return levelData
}

测试用例:

[
  1,      // 0: 1
  1,      // 0: 2
  1,      // 0: 3
  1,      // 0: 4
  [       // 0: 5
    2,    // 1: 1
    2,    // 1: 2
    2     // 1: 3
  ], 
  [       // 0: 6
    [     // 1: 4
      3,  // 2: 1
      3   // 2: 2
    ],   
    [     // 1: 5
      [   // 2: 3
        4 // 3: 1
      ]
    ]
  ]
].elementsAtLevels()

// Object [ 6, 5, 3, 1 ]

问题: 有没有更有效的方法来计算它?

4 个答案:

答案 0 :(得分:1)

我写了一些非常类似于你所拥有的东西,而且在一个非常基本的基准测试中,它的运行时间不到一半。

let a = [1,1,1,1,[2,2,2],[[3,3],[[4]]]];

Array.prototype.elementsAtLevels2 = function (level, lData) {
    if (!level || !lData) {
        level = 0;
        lData = {};
    }

    if (!(level in lData)) {
        lData[level] = this.length;
    } else {
        lData[level] += this.length;
    }
    this.forEach(function (v) {
        if (Array.isArray(v))
            v.elementsAtLevels2(level + 1, lData);
    });

    return lData;
}

console.log(a.elementsAtLevels2());

我猜测主要的性能提升可能来自forEach vs mapmap会创建一个新数组,其中forEach没有。

编辑

此处位于JSBin

答案 1 :(得分:0)

这个递归函数应该做的工作

let arr = [1,1,1,1,[2,2,2],[[3,3],[[4]]]];        

Array.prototype.elementsAtLevels = function(){
   return this.reduce((acc, el, index, currentArray) => {
     if(Array.isArray(el)){
       return acc.concat(el.elementsAtLevels());
     }
     return [currentArray.length];
   }, [])
 }
    
 console.log(arr.elementsAtLevels());

答案 2 :(得分:0)

这个东西和你的一样,但至少它给出了正确的结果:

function elementsAtLevel( array, result = [], level = 0 ){

   result[level] = (result[level] || 0) + array.length
   level++
   for( const el of array ){
      if( Array.isArray(el) )
         elementsAtLevel(el, result, level)
   }
   return result

}

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

正确我的意思是一致:你把子阵列计算为第一级的元素,而不是其他任何元素。

这是一个原型版本:

Array.prototype.elementsAtLevel = function( result = [], level = 0 ){

   result[level] = (result[level] || 0) + this.length
   level++
   for( const el of this ){
      if( Array.isArray(el) )
         el.elementsAtLevel(result, level)
   }
   return result

}

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

答案 3 :(得分:0)

这是我的看法。它类似于你的,但它不会改变原型,它使用数组而不是对象来返回。



function arrayCounter(arr, level, levelData) {
  if (level === void 0) {
    level = 0;
  }
  if (levelData === void 0) {
    levelData = [];
  }
  //Set default value for level
  if (levelData[level] === void 0) {
    levelData[level] = 0;
  }
  //Count length
  levelData[level] += arr.length;
  //Loop through list items
  for (var i = 0; i < arr.length; i++) {
    var value = arr[i];
    //If array, perform a subcount
    if (Array.isArray(value)) {
      levelData = arrayCounter(value, level + 1, levelData);
    }
  }
  return levelData;
}
//TEST
var data = [1, 1, 1, 1, [2, 2, 2],
  [
    [3, 3],
    [
      [4]
    ]
  ]
];

console.log(arrayCounter(data));
&#13;
&#13;
&#13;