Учитывая массив объектов, как мне отсортировать объекты по свойству на глубине n

#javascript #sorting

#javascript #сортировка

Вопрос:

У меня есть массив объектов, которые я хочу отсортировать по некоторым данным свойства группировки, и строка, указывающая мне, по какому свойству группировать (например: «Организация» или «Организация.Имя’)

Мне нужно написать функцию, которая принимает данные, которые выглядят как beforeData и возвращает afterData

Ввод :

 beforeData = [
{'name':'John Doe', 'Id':1, 'Organizations':[{'Id':12, 'LongName': 'Group A'},{'Id':13, 'LongName': 'Group B'}]},
{'name':'FooBar', 'Id':2, 'Organizations':[{'Id':13, 'LongName': 'Group B'},{'Id':14, 'LongName': 'Group C'}]},
{'name':'Kristine Bell', 'Id':3, 'Organizations':[{'Id':12, 'LongName': 'Group A'}]},
{'name':'Adrian P', 'Id':4, 'Organizations':[{'Id':12, 'LongName': 'Group A'}]}
]
 

Вывод:

     afterData = [
    {   
        'Group': 'Group A', 
        'entities':[
            {'name':'Adrian P', 'Id':4, 'Organizations':[{'Id':12, 'LongName': 'Group A'}]},
            {'name':'Kristine Bell', 'Id':3, 'Organizations':[{'Id':12, 'LongName': 'Group A'}]},
            {'name':'John Doe', 'Id':1, 'Organizations':[{'Id':12, 'LongName': 'Group A'},{'Id':13, 'LongName': 'Group B'}]}]
    },
    {   
        'Group': 'Group B', 
        'entities':[
            {'name':'John Doe', 'Id':1, 'Organizations':[{'Id':12, 'LongName': 'Group A'},{'Id':13, 'LongName': 'Group B'}]},
            {'name':'FooBar', 'Id':2, 'Organizations':[{'Id':13, 'LongName': 'Group B'},{'Id':13, 'LongName': 'Group C'}]},]
    },
    {   
        'Group': 'Group C', 
        'entities':[
            {'name':'FooBar', 'Id':2, 'Organizations':[{'Id':13, 'LongName': 'Group B'},{'Id':13, 'LongName': 'Group C'}]},]
    }
]
 

Как бы мне это сделать? Мои текущие попытки чрезвычайно раздуты и занимают целую вечность, учитывая большие наборы данных.

Особый удар!: функция, которая решает эту проблему, должна быть в состоянии решить ее, не зная заранее, находится ли «группа по свойству» на глубине 1 или 2 (например: «Организация» или «Организация.Длинное имя’).

Ответ №1:

Что-то от меня:

 // this function performs data extraction from an object
// the first argument is a name of the property to be extracted
// it might be just a 1st level deep value like `name`
// or nested like `foo.bar.baz`
// in case if one of intermediate items is an array - an array of
// results is returned
function dot(name, obj) {
    if (!name) {
        return obj;
    }

    var match = name.match(/^([^.] )(?:.(.*))?$/),
        head = match[1],
        tail = match[2];

    if (Array.isArray(obj)) {
        return obj.map(function(item) {
            return dot(name, item);
        });
    }

    if (obj === null || typeof obj != 'object') {
        return null;
    }

    return dot(tail, obj[head]);
}

// this function accepts an array of data and a key to group by
// as a result it returns an object with keys equal to a group by key
// and values that hold that key
function groupBy(data, key) {
    return data.reduce(function(result, item) {
        var keys = dot(key, item);
        if (!Array.isArray(keys)) {
            keys = [keys];
        }

        keys.forEach(function(key) {
            if (!(key in result)) {
                result[key] = [];
            }

            result[key].push(item);
        });

        return resu<
    }, {});
}

console.log(groupBy(beforeData, 'Organizations.LongName'));
 

JSFiddle: http://jsfiddle.net/w8N4j /

Теперь его можно легко переформатировать в любой другой формат, который вы хотите.

Например, чтобы получить точный формат из вопроса, вот крошечный трансформатор:

 function transformerExample(hash) {
    var result = [];
    for (var key in hash) if (hash.hasOwnProperty(key)) {
        result.push({
            Group: key,
            entities: hash[key]
        });
    }

    return resu<
}
 

PS: основная реализация, очевидно, может не обрабатывать все возможные ошибки. В зависимости от фактических требований его нетрудно улучшить.

Комментарии:

1. Было бы неплохо получить некоторое объяснение. Просто дамп кода не очень полезен.

2. for (var key in hash) if (hash.hasOwnProperty(key)) { <— опечатка, или это только у меня?

3. @Mauno V.: вовсе нет. Что вас здесь смущает?

4. @zerkms хорошо, раньше не видел, чтобы это так писалось 🙂 Я имею в виду ту часть, которую вы не используете { after for .. но с if

5. @Mauno V.: да 🙂 В зависимости от конкретного проекта стиль кода может быть непринят, но если это так — просто удобный способ перебора объекта, поскольку нам hasOwnProperty все равно нужно проверять. Итак, используя эту форму, я сохраняю одну } , всего 2 строки и одно дополнительное дополнение.