扁平化数组或对象,请设计一个flat,实际工作中经常碰到,面试也常常会遇到这种面试题,所以接下来咱们一起详细分析如何实现这个flat的具体步骤。
数组flat
将多维数组转换成一维数组,例如:['a', ['b', 'c', ['d', 'e', 'f', ['g']]]]
转成['a', 'b', 'c', 'd', 'e', 'f', 'g']
。如何实现flat函数?
方法一、递归
「步骤:」
创建一个空的新数组;
遍历多维数组;
如果当前元素是非数组,将元素添加到新数组末尾;
如果当前元素是数组,元素调用函数本身;
返回新数组。
let arr = ['a', ['b', 'c', ['d', 'e', 'f', ['g']]]];
function flat(array){
let arr = [];
array.forEach(item=>{
if(Array.isArray(item)){
arr = arr.concat(flat(item));
}else{
arr.push(item);
}
});
return arr;
}
flat(arr);
// => ['a', 'b', 'c', 'd', 'e', 'f', 'g']
方法二、非递归
「步骤:」
创建一个空的新数组;
创建一个队列;
循环遍历队列,每次移除首个元素;
如果首个元素是非数组,将首个元素添加到新数组开头;
如果首个元素是数组,将首个元素添加到队列的末尾;
返回新数组。
let arr = ['a', ['b', 'c', ['d', 'e', 'f', ['g']]]];
function flat(array){
let arr = [];
let queue = array;
if(!queue.length){
return [];
}
while(queue.length){
let val = queue.pop();
if(Array.isArray(val)){
queue.push(...val);
}else{
arr.unshift(val);
}
}
return arr;
}
flat(arr);
// => ['a', 'b', 'c', 'd', 'e', 'f', 'g']
对象flat
如果是对象又如何处理呢,例如:{a:{b:{c:{d:'qdkabcd'}},d:{x: 'qdkadx'},e:'qdkae'}}
转成{'a.e':'qdkae','a.d.x':'qdkadx','a.b.c.d':'qdkabcd'}
。
方法一、递归
「步骤:」
创建一个空新对象;
遍历对象属性;
如果当前属性是基本类型,将属性及值复制到新对象上;
如果当前属性是引用类型,将属性及值递归调用函数本身;
返回新对象。
let object = {
a: {
b: {
c: {
d: 'qdkabcd'
}
},
d: {
x: 'qdkadx'
},
e: 'qdkae'
}
};
function flat(object, prefix){
let res = {};
Object.entries(object).forEach(item=>{
let [k, v] = item;
let key = prefix?`${prefix}.${k}`:k;
if(typeof v!= 'object'){
res[key] = v;
}else{
res = Object.assign(res, flat(v, key));
}
});
return res;
}
flat(object);
/*
{
'a.b.c.d': 'qdkabcd',
'a.d.x': 'qdkadx',
'a.e': 'qdkae'
}
*/
方法二:非递归
「步骤:」
创建一个空新对象;
创建一个队列;
循环遍历队列,每次移除首个元素键值对数组;
如果首个元素键值对数组的值是基本类型,将键及值复制到新对象上;
如果首个元素键值对数组的值是引用类型,将键及值添加到队列的末尾;
返回新对象。
let object = {
a: {
b: {
c: {
d: 'qdkabcd'
}
},
d: {
x: 'qdkadx'
},
e: 'qdkae'
}
};
function flat(object){
let res = {};
let queue = Object.entries(object);
while(queue.length){
let [key, obj] = queue.pop();
Object.entries(obj).forEach(item=>{
let [k, v] = item;
if(typeof v!= 'object'){
res[`${key}.${k}`] = v;
}else{
queue.push([`${key}.${k}`, v]);
}
});
}
return res;
}
flat(object);
/*
{
'a.e': 'qdkae',
'a.d.x': 'qdkadx',
'a.b.c.d': 'qdkabcd'
}
*/
总结
递归是指直接或间接调用函数本身,也成为线性递归。特点:代码精炼,易于阅读,性能差。非递归是指借助堆栈或者循环算法实现。代码复杂,不易理解,性能好。