使阵列平坦,理解解决方案

时间:2016-06-25 18:33:31

标签: javascript arrays

我几天前发布了一个问题,关于如何在不使用concatreduce的情况下展平数组,我得到了一些很好的答案,但我仍然不能完全理解我收到的解决方案。我会尽力理解每一行,也许有人可以指出我的推理错误。

function flatten(array) {
    var l = array.length, temp;
    while (l--) {
        if (Array.isArray(array[l])) {
            flatten(array[l]);
            temp = array[l].slice();
            temp.unshift(1);
            temp.unshift(l);
            [].splice.apply(array, temp);
        }
    }
}


var array = [['1', '2', '3'], ['4', '5', ['6'], ['7', '8']]];

flatten(array);

console.log(array);

好的,首先

var l = array.length, temp;

这里l只是2,因此我们的数组长度为2,temp为2

if (Array.isArray(array[l]))

如果位置1的数组(因为我们在l循环中将1递减while)确实是一个数组,我们将执行代码的下一部分

flatten(array[l]);

这里我们需要继续,以防我们在数组中嵌套数组

temp = array[l].slice();

因为切片没有参数temp = array[1];所以现在temp = ['4', '5', ['6'], ['7', '8']]]

temp.unshift(1);

在temp的开头添加一个。 (不知道为什么我们这样做,以及为什么排名第一)

temp.unshift(l);

由于l1,我们会在数组的开头添加另一个1

现在temp = [1,1,'4', '5', ['6'], ['7', '8']]

[].splice.apply(array, temp);好吧,我真的不知道这条线在做什么。我一直在阅读文档,我理解apply允许我们为this指定一个值然后我们可以传递一些参数并运行一个函数(对于我看到的例子),但我可以&#39 ;了解这里的用法是什么。加拼接从索引x中取出y个元素,那么这些索引是什么?这里splice没有参数。并且在开头[]中使用空数组。请帮助我理解我真的很努力!

4 个答案:

答案 0 :(得分:1)

所以你的问题是关于代码的这一部分:

        temp.unshift(1);
        temp.unshift(l);
        [].splice.apply(array, temp);

从最后一个语句开始,它在splice上调用array,但是以特定的方式。通常你会这样称呼它:

array.splice(l, 1, temp[0], temp[1], ...)

...表示:在l的索引array,删除1个元素,然后插入temp[0]temp[1],...等问题是我们事先并不知道temp中有多少元素,但仍需要向splice提供尽可能多的参数。我们不能只将temp作为参数传递,因为array会插入一个数组本身的元素,这就是你只是想要的做。

虽然在ES6中有一个简单的解决方案(见下文),但在ES5中,您可以使用apply上的splice来解决此问题。 apply方法接受将函数应用于的第一个参数,然后是一个包含需要传递给该函数的所有参数的数组。

由于这两个参数中的前两个具有索引的含义,以及要删除的元素数(见上文),然后其余参数表示需要插入哪些元素(temp中的元素),所有这一切都发生了变化:这些插入了两个第一个参数传递给splice

然后剩余的参数是最初在temp中的变量(在变换之前)。您可以说shiftapply语句执行以下操作:

array.splice(temp[0], temp[1], temp[3], temp[4], ...)

注意temp现在如何为所有参数扮演角色。这就是前两个值被移入的原因。它看起来很复杂,虽然它有效,但它不会产生非常易读的代码。

现在在ES6中,它变得更加简单。您现在可以使用扩展运算符将数组分解为不同的参数,函数可以处理:

array.splice(l, 1, ...temp)

由于我们不再需要转移,我们可以安全地执行此操作而不使用变量temp,并直接在array[l]上执行此操作。所以完整的代码看起来像这样:



function flatten(array) {
  var l = array.length;
  while (l--) {
    if (Array.isArray(array[l])) {
      flatten(array[l]);
      array.splice(l, 1, ...array[l]);
    }
  }
}


var array = [['1', '2', '3'], ['4', '5', ['6'], ['7', '8']]];

flatten(array);

console.log(array);




不是那么好又简单吗? ; - )

答案 1 :(得分:0)

我认识到来自fcc的挑战​​......但这是一种非常复杂的方式。这是怎么解决的。

function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) { 
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten); 
  }, []);
}
function steamroller(arr) {
 return flatten(arr);
}

steamroller([1, [2], [3, [[4]]]]);

你发布的解决方案是非常复杂,混乱和破碎,最后的解除只是在数组的开头加1,1,这是一个通过挑战的肮脏方式......

答案 2 :(得分:0)

我会这样做这个工作;



var a =[['1', '2', '3'], ['4', '5', ['6'], ['7', ['8','9']]]];
Array.prototype.flat = function(){
  return this.reduce((p,c) => Array.isArray(c) ? p.concat(...c).flat() : p.concat(c),[]);
};
var b = a.flat();
console.log(JSON.stringify(b));




答案 3 :(得分:0)

Splice是一个函数,它从索引开始,要删除的元素数量,以及要插入剩余空洞内部的0+元素。

Apply是一个函数有的方法(是的,函数是对象,有方法)。 它需要一个this,然后需要传入一组参数。

如果您不知道自己有多少元素,但需要将它们全部传递给函数:

// instead of
fn(a, b, c, d, e, f, g);

// you can say
fn.apply(null, args); // args being an array of arbitrary length

所以你可以说:

array.splice.apply(array, args);

其中args应该是索引,要删除的数字,然后是放在该洞内的任意元素列表。

[]只是一个可以快速访问splice(通过apply调用它)的一次性数组。