使用路径从对象中提取数据 - 包括数组中的所有数据

Extract data from object using a path - include all data in arrays

我正在尝试用 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]']); (link),但据我所知,它不支持折叠整个数组。

您可以采用经典的迭代和递归方法,return 仅找到 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; }

我会用简单的 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(","))

为了提取属于每个人的每个轮胎压力的列表,您可以使用 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);

您可以使用 Lodash's flatMap. This could probably get shorter using 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>