Javascript中第n个嵌套数组平坦化的迭代解法

Javascript中第n个嵌套数组平坦化的迭代解法,javascript,arrays,function,Javascript,Arrays,Function,有人能给我看一下下面问题的迭代解决方案吗?我递归地解决了这个问题,但却遇到了一个迭代的解决方案。(Facebook技术采访问题) 解决方案必须使用第n个嵌套数组元素(即,如果有人在上面的示例中修改数组值/位置,则该解决方案必须仍然有效) 递归解决方案: var flatten = function(input) { var result = []; input.forEach(function(element) { result = result.concat(

有人能给我看一下下面问题的迭代解决方案吗?我递归地解决了这个问题,但却遇到了一个迭代的解决方案。(Facebook技术采访问题)

解决方案必须使用第n个嵌套数组元素(即,如果有人在上面的示例中修改数组值/位置,则该解决方案必须仍然有效)

递归解决方案:

var flatten = function(input) {
    var result = [];

    input.forEach(function(element) {
        result = result.concat(Array.isArray(element) ? flatten(element) : element);
    });

    return result;
}

工作,但不建议:

var flatten = function(input) {
    return eval("[" + JSON.stringify(input).
    replace(/\[/g,"").replace(/\]/g,"") + "]");
}

不同的迭代算法:

function flatten2(input) {
  var output = [];
  var todo = [input];
  var current;
  var head;

  while(todo.length) {
    var current = todo.shift();
    if(Array.isArray(current)) {
      current = current.slice();
      head = current.shift();
      if(current.length) {
        todo.unshift(current)
      }

      todo.unshift(head);
    } else {
      output.push(current);
    }
  }

  return output;
}
function flatten(input) {
  var output = [];
  var todo = [input];
  var current;

  while(todo.length) {
    var current = todo.shift();
    if(Array.isArray(current)) {
       todo.unshift.apply(todo, current)
    } else {
      output.push(current);
    }
  }

  return output;
}
  • 将所有元素放在堆栈上
  • 当堆栈不为空时,删除第一个元素。
    • 如果该元素是标量,则将其添加到输出中
    • 如果该元素是数组,则将其拆分为head(第一个元素)和tail(其余元素),并将两者添加到堆栈中
如图所示,这相当缓慢

这里有一种方法:

var input = [1, {a: 2}, [3], [[4, 5], 6], 7];
function flatten(input) {
    var i, placeHolder = [input], lastIndex = [-1], out = [];
    while (placeHolder.length) {
        input = placeHolder.pop();
        i = lastIndex.pop() + 1;
        for (; i < input.length; ++i) {
            if (Array.isArray(input[i])) {
                placeHolder.push(input);
                lastIndex.push(i);
                input = input[i];
                i = -1;
            } else out.push(input[i]);
        }
    }
    return out;
}
flatten(input);
这同样更快(对于平面迭代来说),并且多次调用它的垃圾收集器问题更少。它的速度非常接近Chrome中的递归函数调用,比FireFox和IE中的递归快很多倍

我在这里重新创建了Tomalak的测试,因为旧的jsPerf已被破坏以进行编辑:

这个怎么样

inp=[1,{a:2}[3],[4,5,6],7]
out=inp;
while(out.some(Array.isArray))
out=[].concat.apply([],out);

document.write(JSON.stringify(out))一个相当简洁易读的算法:

function flatten2(input) {
  var output = [];
  var todo = [input];
  var current;
  var head;

  while(todo.length) {
    var current = todo.shift();
    if(Array.isArray(current)) {
      current = current.slice();
      head = current.shift();
      if(current.length) {
        todo.unshift(current)
      }

      todo.unshift(head);
    } else {
      output.push(current);
    }
  }

  return output;
}
function flatten(input) {
  var output = [];
  var todo = [input];
  var current;

  while(todo.length) {
    var current = todo.shift();
    if(Array.isArray(current)) {
       todo.unshift.apply(todo, current)
    } else {
      output.push(current);
    }
  }

  return output;
}
此版本的性能比我的好,但仍然比我的慢很多


这里有一个解决方案,它可以在适当的地方变平

function flatten(arr) {
  var i = 0;

  if (!Array.isArray(arr)) {
    /* return non-array inputs immediately to avoid errors */
    return arr;
  }

  while (i < arr.length) { 
    if (Array.isArray(arr[i])) {
      arr.splice(i, 1, ...arr[i]);
    } else {
      i++;
    }
  }
  return arr;
}
函数展平(arr){
var i=0;
如果(!Array.isArray(arr)){
/*立即返回非数组输入以避免错误*/
返回arr;
}
而(i
此解决方案在数组中迭代,一次将每个元素展平一级嵌套,直到无法再展平为止

函数展平(数组){
function flatten(array){
  for(var i=0;i<array.length;i++)
    if(Array.isArray(array[i]))
      array.splice.apply(array,[i,1].concat(array[i--]));
  return array;
}

对于(var i=0;i,这里有两种方法,递归和迭代,以及它们与Array.flat的比较。 也许它会帮助别人

const arraytoflant=[[1],[2[3]],null,[[{}]],未定义];
//获取数组并递归展平,默认深度为1(与array.flat()类似)
函数(arr,深度=1){
让myArray=[];
如果(深度===0){//如果已达到深度,请不要继续
myArray=arr;
}else如果(!Array.isArray(arr)){//如果不是数组,则将项添加到数组中
myArray.push(arr);
}else{//展平数组中的每个项,然后连接
arr.forEach(项目=>{
const someNewArray=递归(项,深度-1);
myArray=myArray.concat(someNewArray);
});
}
返回myArray;
}
//获取一个数组并使用循环将其展平,默认深度为1(与array.flat()类似)
函数(arr,深度=1){
设结果=arr;
//如果元素是数组
while(result.some(Array.isArray)和depth){
//通过浓缩空数组并使用apply将数组展平一级
结果=[].concat.apply([],结果);
深度--;//轨迹深度
}
返回结果;
}
console.log(arraytoflant.flat(2));//ES^
log(flattrecursive(arraytoflant,2));

console.log(flatteIterative(ArrayToFlatte,2));
以下是我的解决方案:

function flattenList(A) {
  let result = []
  for (let i=0; i < A.length; i++) {
    if (typeof A[i] == "object"){
      let item = reduceArray(A[i])
      result.push(...item)
    }else {
      result.push(A[i])
    }
  }
  return result
}

function reduceArray(arr){
  while(arr.some(Array.isArray)) {
    let item = arr.find(Array.isArray)
    let index = arr.indexOf(item)
    arr[index] = item[0]
  }
  return arr
}
功能列表(A){
让结果=[]
for(设i=0;i
出于好奇,你的递归解决方案是什么?可能与此作业重复?你为迭代解决方案做了哪些尝试?如果你已经有了递归解决方案,为什么还要追求迭代解决方案?请将递归解决方案添加到你的问题中,以便正确格式化。多行代码不可读在注释中。出于好奇,输入
[1,{a:[2,3,4]}]
会发生什么?输出是否应该与输入相同或
[1,{a:[2,3,4]}]
(或其他内容)?换句话说,展平过程是应该到达内部对象还是仅仅展平本身就是阵列的元素?与我预期的解决方案不太一样。:)尽管这很糟糕,但它实际上可能能够处理比递归或迭代解决方案更大的数组。一场枪战将是令人敬畏的:-)跳出框框思考的好方法。;)如果数组包含一些字符串,例如
“go to supermarket[…]”
@nopole,那么它将不起作用,但对于带有数字的OPs情况,它确实起作用。另请参阅“但不推荐"。我将删除我的,反正它们是等效的。这可能更符合我认为面试官想要的。@JamesWilkins我已经尝试了更多的平台。你的代码始终是最快的,做得很好。:)谢谢。我在这里也做了类似的事情,以表明有时低级代码虽然复杂,但在spe中可以快得多特殊情况:可能是O(n)其中n是整个嵌套对象结构中的总项数。深度不相关。它可以很容易地成为具有相同项数的单个对象。开销不会像跳转到嵌套数组那样大。仅供参考,到目前为止,我已经为答案做了一个jsPerf:谢谢。我希望性能更清晰-那些
slice
调用很慢。@Tomalak你让我想到了性能:-)这更好,但与James Wilkins的答案不符。我链接了你的JSPerf的一个新版本。这很好。比t更简单,可能更快,内存效率更高