Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

利用Javascript数组对多维数组进行降维 #1

Closed
Jarvis-Q opened this issue May 31, 2019 · 0 comments
Closed

利用Javascript数组对多维数组进行降维 #1

Jarvis-Q opened this issue May 31, 2019 · 0 comments
Labels
articles articles of blog being store here

Comments

@Jarvis-Q
Copy link
Owner

#首先我们来看一道题目:

var arr = [1, 2, [3], [4, 5]];
// 要求转化为 [1, 2, 3, 4, 5]的形式

concat方式

要对数组进行降维操作,这里我们可能普通的思路,就是遍历数组成员。判断其类型,根据类型决定是否要抽取内部成员。

var origin = [1, 2, [3], [4, 5]];

function transArray (arr) {
    var arr2 = [];
    for (var i = 0; i < arr.length; i++) {
        var item = arr[i];
        if (typeof item === 'number') {
            arr2.push(item);
        } else if (typeof item === 'object') {
            arr2 = arr2.concat(item);
        }
    }
    return arr2;
}

console.log('输出:%o', transArray(origin));
// 输出:(5) [1, 2, 3, 4, 5]

toString方式

假如这时候我们希望转化为字符串类型的
["1", "2", "3", "4", "5"]
那么可以直接调用数组的toString方法把数组成员都转化成字符串以后,通过分割方法转成数组

var origin = [1, 2, [3], [4, 5]];

function transArray (arr) {
    return arr.toString().split(',');
}

console.log('输出:%o', transArray(origin));
// 输出["1", "2", "3", "4", "5"]

Number、Boolean、String、Array、Date、RegExp、Function这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法. 同样[]其实是Array的实例,所以[3],[4,5]也被转化为字符串形式了'3', '4, 5'

###Apply方式?
其实这种方式本质上和concat是一样的。最后实现都是依赖concat。这里唯一的区别是利用apply的方式,可以自动解析类数组和数组,用的是内建的函数,所以在时间复杂度上是否有区别呢?这个需要带考证。

Array.prototype.concat.apply(origin)

不给过这种方法的弊端是只能解决二维的降维。所以我们需要引入递归来解决这个多维数组降维的方法。

递归降维

其实就是方式1的变种, 但由于其采用递归方式,可以支持多维数组的降维。

var origin = [1, 2, [3, [4, 5]]];

function transArray (arr) {
    var arr2 = [];
    for (var i = 0; i < arr.length; i++) {
        var item = arr[i];
        if (Array.isArray(item)) {
            // 如果是es5,判断item是否为Array的实例
            // item instanceof Array
            arr2.push.apply(arr2, transArray(item));
        } else {
            arr2.push(item);
        }
    }
    return arr2;
}

console.log('输出:%o', transArray(origin));
// 输出:(5) [1, 2, 3, 4, 5]

其他

  1. Array.prototype.map+递归
    在网络上搜索,你会发现还有map函数对每个成员进行处理,其思想依然是需要判断当前的数组成员是否为数组,从从进行额外处理,对于多维数组而言,仍然需要递归处理去内部成员对象。

  2. Array.prototype.reduce+递归
    reduce这种迭代器也是同样的道理,只是采用不同的方式来对数组成员进行遍历,需要关注比较的在数据量上的时间和空间的成本。

reduce的好处之一是可以明显的简化代码, 这次我们把源数组的类型增多。

const arr = [
    1,
    [2, '3'], 
    { name: '数组' }, 
    false, 
    ['a[b]c', 'd,e,f', [[4]]], 
    [{g: 5}]
]

// 注意reduce最好设置初始值,否则当只有一个元素时,会返回数组对象本身。
function flatten(arr) {
    return arr.reduce((prev, next) => {
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}

// 输出3:(10) [1, 3, "4", {name: '数组'}, false, "a[b]c", "d,e,f", 4, {g: 5}]

mapreduce以及while其实在不同的浏览器JS引擎下表现的性能和内存消耗是不一样的,甚至可能是相反的。

对于性能表现这块有深掘的,可以看下有赞这个作者的实测. JS数组循环的性能和效率分析(for、while、forEach、map、forof)

@Jarvis-Q Jarvis-Q added the articles articles of blog being store here label May 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
articles articles of blog being store here
Projects
None yet
Development

No branches or pull requests

1 participant