Извлечь данные из объекта, используя путь - включить все данные в массивы - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь решить следующую проблему с LoDash. Я знаю, как решить проблему, используя циклы for, но ищу современный функциональный метод решения проблемы.


У меня есть следующие данные:

const data = {
    people: [
        {
            name: "Bob",
            vehicles: [
                {
                    model: "Mazda"
                    tires: [
                        { pressure: 20 },
                        { pressure: 22 },
                        { pressure: 23 },
                        { pressure: 21 },
                    ]
                },
                {
                    model: "Harley Davidson"
                    tires: [
                        { pressure: 20 }
                        { pressure: 25 }
                    ]
                }
            ]
        },
        {...},
        {...},
        {...},
    ]
}

Из него я хочу извлечь список всех давлений в шинах, принадлежащих каждому человеку. Итак, как-то так:

[20, 22, 23, 21, 20, 25, ... ]

То, что я ищу, - это метод, который я могу назвать так:

const path = 'people.vehicles[*].tires[*].pressure';
const tirePressure = _.methodName(data, path);

Я знаю, что lodash поддерживает некоторые подобные функции - например, _.at(object, ['a[0].b.c', 'a[1]']); (ссылка) , но, насколько я могу судить, он не поддерживает свертывание всего массива.

Ответы [ 4 ]

0 голосов
/ 06 июля 2018

Этого можно добиться, используя Лодаша flatMap. Вероятно, это может быть короче, если использовать flatMapDeep, но в этом случае ИМХО гораздо понятнее.

const data = {
    people: [
        {
            name: "Bob",
            vehicles: [
                {
                    model: "Mazda",
                    tires: [
                        { pressure: 20 },
                        { pressure: 22 },
                        { pressure: 23 },
                        { pressure: 21 },
                    ]
                },
                {
                    model: "Harley Davidson",
                    tires: [
                        { pressure: 20 },
                        { pressure: 25 }
                    ]
                }
            ]
        }
    ]
};


const pressures = _(data.people)
  .flatMap(_.property('vehicles'))
  .flatMap(_.property('tires'))
  .map(_.property('pressure'))
  .value();

console.log(pressures);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
0 голосов
/ 05 июля 2018

Я бы сделал с простыми JS, как

Используйте .map, чтобы получить значения шин, а затем сгладить этот массив

const data = {
    people: [
        {
            name: "Bob",
            vehicles: [
                {
                    model: "Mazda",
                    tires: [
                        { pressure: 20 },
                        { pressure: 22 },
                        { pressure: 23 },
                        { pressure: 21 },
                    ]
                },
                {
                    model: "Harley Davidson",
                    tires: [
                        { pressure: 20 },
                        { pressure: 25 }
                    ]
                }
            ]
        }
    ]
}
var x=  data.people[0].vehicles.map(o=> o.tires.map(i=> i.pressure))

console.log(x.join(",").split(","))
0 голосов
/ 05 июля 2018

Чтобы извлечь список всех давлений в шинах, принадлежащих каждому человеку, вы можете использовать reduce и сгруппировать все значения давления в шинах по соответствующему имени, а также использовать структуру данных объекта для сохранения выходных данных:

const data={people:[{name:"Bob",vehicles:[{model:"Mazda",tires:[{pressure:20},{pressure:22},{pressure:23},{pressure:21}]},{model:"Harley Davidson",tires:[{pressure:20},{pressure:25}]}]}]};

const result = data.people.reduce((all, {name, vehicles}) => {

  const pressures  = vehicles.reduce((total, {tires}) => {
    tires.forEach(({pressure}) => total.push(pressure));
    return total;
  }, []);

  all[name] = pressures;

  return all;

}, {});

console.log(result);
0 голосов
/ 05 июля 2018

Вы можете использовать классический итеративный и рекурсивный подход и возвращать только найденные значения pressure.

function getPressures(o) {
    return [].concat(...Object.entries(o).map(([key, value]) =>
        key === 'pressure'
            ? value
            : value && typeof value === 'object'
                ? getPressures(value)
                : []
    ));
}

var data = { people: [{ name: "Bob", vehicles: [{ model: "Mazda", tires: [{ pressure: 20 }, { pressure: 22 }, { pressure: 23 }, { pressure: 21 }] }, { model: "Harley Davidson", tires: [{ pressure: 20 }, { pressure: 25 }] }] }] };

console.log(getPressures(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Другой подход заключается в реализации метода get для пути с символами подстановки, в результате получается объект с путями в качестве ключей и требуемыми значениями.

function get(object, path) {

    function iter(o, p, i) {
        if (i === parts.length) {
            result[p.join('.')] = o;
            return;
        }
        if (!o || typeof o !== 'object') {
            return;
        }
        if (parts[i] === '*') {
            Object
                .entries(o)
                .forEach(([k, v]) => iter(v, p.concat(k), i + 1));
            return;
        }
        if (parts[i] in o) {
            iter(o[parts[i]], p.concat(parts[i]), i + 1);
        }
    }

    var result = {},
        parts = path.split('.');

    iter(object, [], 0);
    return result;
}

var data = { people: [{ name: "Bob", vehicles: [{ model: "Mazda", tires: [{ pressure: 20 }, { pressure: 22 }, { pressure: 23 }, { pressure: 21 }] }, { model: "Harley Davidson", tires: [{ pressure: 20 }, { pressure: 25 }] }] }] },
    result = get(data, 'people.*.vehicles.*.tires.*.pressure'),
    values = Object.values(result);

console.log(result);
console.log(values);
.as-console-wrapper { max-height: 100% !important; top: 0; }
...