Вложить / сгруппировать массив объектов по атрибуту, игнорируя null / undefined и используя дополнительное свойство в качестве метки - PullRequest
0 голосов
/ 07 мая 2018

Я пытаюсь сгруппировать массив объектов.

Функция, предоставляемая этой сущностью, почти работает как задумано и использует 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. если для параметра установлено значение null или undefined, он используется как группа, вместо
  2. необязательный атрибут объекта должен использоваться в качестве конечного ключа объекта, поэтому есть только объекты, но не массивы. Этот атрибут всегда должен быть уникальным для правильной работы.

Возможно ли объединить или расширить существующую функцию 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 голосов
/ 07 мая 2018

Вот способ сделать это в Vanilla JS. Мы создаем объект result с помощью reduce массива seq: для каждого объекта obj в массиве seq мы проходим уровень объекта result по уровню, используя значения из obj ключи от keys. Если значение равно null или undefined, мы пропускаем (не перейдем на другой уровень). Если значение существует, мы понижаем уровень, создавая уровень (объект), если он еще не существует. Мы делаем это многократно, используя 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);
...