对象扁平化

1,330 阅读3分钟

解题进化路,还是自己太菜

/**
  * 题目: 对象扁平化,不考虑环引用的情况
  * 说明:请实现 flatten(input) 函数,input 为一个 javascript 对象(Object 或者 Array),返回值为扁平化后的结果。
  * 示例:
  *   let input = {
  *     a: 1,
  *     b: [ 1, 2, { c: true }, [ 3 ] ],
  *     d: { e: 2, f: 3 },
  *     g: null, 
  *   }
  
  *   let output = flatten(input);
  *   output如下
  *   {
  *     "a": 1,
  *     "b[0]": 1,
  *     "b[1]": 2,
  *     "b[2].c": true,
  *     "b[3][0]": 3,
  *     "d.e": 2,
  *     "d.f": 3,
  *     // "g": null,  值为null或者undefined,丢弃
  *  }
*/

解题进化过程

第一次

第一次(钻牛角尖了,看到题目是字符串形式的key,获取字符串key整个过程有点复杂了)

function flatten(input) {
    let temp = input;
    let result = {};
    let keyArr = Object.getOwnPropertyNames(input);
    keyArr.forEach((key) => {
        // null undefined
        if (temp[key] === "undefined" || Object.is(temp[key], null)) {
            return;
        } else if (typeof temp[key] === "object") {
            // 数组、对象递归
            if (Array.isArray(temp[key])) {
                temp[key].forEach((item, index) => {
                    if (typeof item === "object") {
                        result = Object.assign(
                            {},
                            result,
                            flatten(
                                Object.defineProperty(
                                    {},
                                    key + "[" + index + "]",
                                    { value: item }
                                )
                            )
                        );
                    } else {
                        result['"' + key + "[" + index + ']"'] = item;
                    }
                });
            } else {
                for (let childKey in temp[key]) {
                    if (typeof temp[key][childKey] === "object") {
                        result = Object.assign(
                            {},
                            result,
                            flatten(
                                Object.defineProperty(
                                    {},
                                    key + "." + childKey,
                                    { value: temp[key][childKey] }
                                )
                            )
                        );
                    } else {
                        result['"' + key + "." + childKey + '"'] =
                            temp[key][childKey];
                    }
                }
            }
        } else {
            // 普通类型
            result['"' + key + '"'] = temp[key];
        }
    });
    return result;
}
let input = {
    a: 1,
    b: [1, 2, { c: true }, [3]],
    d: { e: 2, f: 3 },
    g: null,
};
console.log("output1", flatten(input));

第二次

第二次,代码精简很多不考虑字符串的key,但是在外部引入一个全局变量result

let result = {};
function flatten(input) {
    const temp = input;
    const parentKey = Array.from(arguments)[1];
    if (input instanceof Array) {
        input.forEach((item, index) => {
            if (typeof item === "object") {
                flatten(item, `${parentKey}[${index}]`);
            } else {
                result[`${parentKey}[${index}]`] = flatten(
                    item,
                    `${parentKey}[${index}]`
                );
            }
        });
    } else if (input instanceof Object) {
        for (let key in input) {
            if (typeof input[key] === "object") {
                if (parentKey) {
                    flatten(input[key], parentKey + "." + key);
                } else {
                    flatten(input[key], key);
                }
            } else if (
                input[key] === "undefined" ||
                Object.is(input[key], null)
            ) {
                continue;
            } else {
                if (parentKey) {
                    result[`${parentKey}.${key}`] = flatten(
                        input[key],
                        key
                    );
                } else {
                    result[key] = flatten(input[key], key);
                }
            }
        }
    } else {
        return input;
    }
}

let input = {
    a: 1,
    b: [1, 2, { c: true }, [3]],
    d: { e: 2, f: 3 },
    g: null,
};
flatten(input)
console.log("output1", result);

第三次

第三次,(定义一个内部函数,这样就可以自定义新函数的入参)

function flatten(input) {
    let result = {};
    function flattenFn(input, parentKey) {
        if (input instanceof Array) {
            input.forEach((item, index) => {
                if (typeof item === "object") {
                    flattenFn(item, `${parentKey}[${index}]`);
                } else {
                    result[`${parentKey}[${index}]`] = flattenFn(
                        item,
                        `${parentKey}[${index}]`
                    );
                }
            });
        } else if (input instanceof Object) {
            for (let key in input) {
                if (typeof input[key] === "object") {
                    if (parentKey) {
                        flattenFn(input[key], parentKey + "." + key);
                    } else {
                        flattenFn(input[key], key);
                    }
                } else if (
                    input[key] === "undefined" ||
                    Object.is(input[key], null)
                ) {
                    continue;
                } else {
                    if (parentKey) {
                        result[`${parentKey}.${key}`] = flattenFn(
                            input[key],
                            key
                        );
                    } else {
                        result[key] = flattenFn(input[key], key);
                    }
                }
            }
        } else {
            return input;
        }
    }
    flattenFn(input);
    return result;
}

let input = {
    a: 1,
    b: [1, 2, { c: true }, [3]],
    d: { e: 2, f: 3 },
    g: null,
};
console.log("output1", flatten(input));

第四次(最终版)

以为第三版本就是最终版了,没想到进一步抽离部分内容,代码还可以精简

function flatten(input) {
    let result = {};
    function flattenFn(obj, parentKey) {
        if (obj instanceof Array) {
            /**
             * array遍历
             * 引用类型执行递归
             * 基础类型直接处理
             */
            obj.forEach((item, index) => {
                // 如果input直接就是数组,需要确认展开形式进一步增加判断
                let newKey = parentKey + "[" + index + "]";
                if (typeof item === "object") {
                    flattenFn(item, newKey);
                } else {
                    result[newKey] = item;
                }
            });
        } else if (obj instanceof Object) {
            /**
             * object遍历
             * 引用类型执行递归
             * null、undefined特殊处理
             * 基础类型直接处理
             */
            for (let key in obj) {
                let value = obj[key];
                let newKey = parentKey ? parentKey + "." + key : key;
                if (typeof value === "object") {
                    flattenFn(value, newKey);
                } else if (value === undefined || value === null) {
                    continue;
                } else {
                    result[newKey] = value;
                }
            }
        }
    }
    flattenFn(input);
    return result;
}

另外,第三种方法也可以返回一个闭包函数,但是可能会调用两次函数(也可能我这边思路有问题hhh)

如果还有最优解,欢迎大佬们评论回复呀