按属性嵌套/分组对象数组,忽略null / undefined并使用其他属性作为标签

时间:2018-05-07 12:00:20

标签: javascript lodash

我正在尝试对一组对象进行嵌套分组。

这个要点提供的功能几乎按预期工作,并使用lodash作为基础:

https://gist.github.com/joyrexus/9837596

const _ = require('lodash');

function nest(seq, keys) {
    if (!keys.length) return seq;
    let [first, ...rest] = keys;
    return _.mapValues(_.groupBy(seq, first), value => nest(value, rest));
}

这是递归的,

但是,我面临两个问题。

  1. 如果参数设置为nullundefined,则将其用作组,而不是
  2. 应该使用可选的对象属性作为最终的对象键,因此只有对象,没有数组。此属性始终必须是唯一的才能正常工作。
  3. 是否可以组合或扩展现有的nest函数来解决上述问题?

    这种方法的优点是,我还可以使用函数数组(p => p.parameterGroup1)来代替键,以返回参数。因此,我也可以使用p => p.parameterGroup1 ? p.parameterGroup1 : p.label

    代替最后一个可选参数

    我准备了一点测试,让你更好地了解预期:

    test('nest array of objects by groups as keys, stopping at null and using a final label param', t => {
        let properties = [
            {
                parameterGroup1: 'first',
                parameterGroup2: 'second',
                parameterGroup3: 'third',
                label: 'A'
            },
            {
                parameterGroup1: 'first',
                parameterGroup2: 'second',
                parameterGroup3: null,
                label: 'B'
            },
            {
                parameterGroup1: 'a',
                parameterGroup2: 'b',
                parameterGroup3: undefined,
                label: 'C'
            },
        ]
        let expected = {
            first: {
                second: {
                    third: {
                        A: {
                            parameterGroup1: 'first',
                            parameterGroup2: 'second',
                            parameterGroup3: 'third',
                            label: 'A'
                        }
                    },
                    B: {
                        parameterGroup1: 'first',
                        parameterGroup2: 'second',
                        parameterGroup3: null,
                        label: 'B'
                    }
                }
            },
            a: {
                b: {
                    C: {
                        parameterGroup1: 'a',
                        parameterGroup2: 'b',
                        parameterGroup3: undefined,
                        label: 'C'
                    }
                }
            }
        }
        let grouped = nest(properties, ['parameterGroup1', 'parameterGroup2', 'parameterGroup3'], 'label')
        t.deepEqual(grouped, expected)
    })
    

    提前谢谢!

1 个答案:

答案 0 :(得分:1)

这是一种在vanilla js中执行此操作的方法。我们通过result数组reduce构造seq对象:对于数组obj中的每个对象seq,我们遍历result对象使用来自obj的密钥的keys的值逐级进行排名。如果值为nullundefined,我们会跳过(不会再下一个级别)。如果值存在,我们会下降一个级别,如果它不存在则创建一个级别(对象)。我们使用reduce数组上的keys重复执行此操作,直到我们找到叶对象(最后一级),我们将当前对象分配给获得的评估obj[last]的密钥:

function nest(seq, keys, last) {
    return seq.reduce((result, obj) => {
        // First we find the (last level) object to which we will assign our current object to, as a child
        let lastLevel = keys.reduce((res, key) => {               // for each key in keys
            let value = obj[key];                                 // get the value from our current object obj for that key key
            if(value == null) return res;                         // if the value is null or undefined, skip
            if(res[value]) return res[value];                     // if the level for value exists return it
            return res[value] = {};                               // if it doesn't, create a new level, assing it to result and return it
        }, result);

        // then we assign it using the value of the key last
        lastLevel[obj[last]] = obj;                               // we found the last possible level, assign obj to it under the key obj[last]

        return result;
    }, {});
}

示例:

function nest(seq, keys, last) {
    return seq.reduce((result, obj) => {
        let lastLevel = keys.reduce((res, key) => {
            let value = obj[key];
            if(!value) return res;
            if(res[value]) return res[value];
            return res[value] = {};
        }, result);
        lastLevel[obj[last]] = obj;
        return result;
    }, {});
}



let properties = [{parameterGroup1: 'first',parameterGroup2: 'second',parameterGroup3: 'third',label: 'A'},{parameterGroup1: 'first',parameterGroup2: 'second',parameterGroup3: null,label: 'B'},{parameterGroup1: 'a',parameterGroup2: 'b',parameterGroup3: undefined,label: 'C'}];

let grouped = nest(properties, ['parameterGroup1', 'parameterGroup2', 'parameterGroup3'], 'label');
console.log(grouped);