[英]Lodash pick from deep array
I have an complex Object我有一个复杂的对象
{
"a": 1,
"b": {"test": {
"b1": 'b1'
}},
"c": {
"d": [{foo: 1}, {foo: 2}, {foo: 3, bar: 1}, {bar: 12}]
},
}
And I have list of keys:我有钥匙列表:
[
"a",
"b.test.b1",
"c.d[].foo"
]
What I want to do - is to pick all values I have keys for.我想要做的 - 是选择我有键的所有值。 The problem is - I do not sure how to handle arrays (
"cd[].foo"
).问题是 - 我不知道如何处理数组(
"cd[].foo"
)。 I do not know how long the array is and which elements do or do not have foo
我不知道数组有多长以及哪些元素有或没有
foo
The result should be结果应该是
{
"a": 1,
"b": {"test": {
"b1": 'b1'
}},
"c": {
"d": [{foo: 1}, {foo: 2}, {foo: 3}]
},
}
UPD If someone interested, here is my implementation of this function: UPD如果有人感兴趣,这是我对这个函数的实现:
const deepPick = (input, paths) => {
return paths.reduce((result, path) => {
if(path.indexOf('[]') !== -1) {
if(path.match(/\[\]/g).length !== 1) {
throw new Error(`Multiplie [] is not supported!`);
}
const [head, tail] = path.split('[]');
const array = (get(input, head) || []).reduce((result, item) => {
// if tail is an empty string, we have to return the head value;
if(tail === '') {
return get(input, head);
}
const value = get(item, tail);
if(!isNil(value)) {
result.push(set({} , tail, value));
} else {
result.push(undefined);
}
return result;
}, []);
const existingArray = get(result, head);
if((existingArray || []).length > 0) {
existingArray.forEach((_, i) => {
if(!isNil(get(array[i], tail))) {
set(existingArray, `${i}.${tail}`, get(array[i], tail));
}
});
} else if(array.length > 0) {
set(result, head, array);
}
} else {
set(result, path, get(input, path));
}
return result;
}, {});
}
map-factory
might help to do this task in elegant way. map-factory
可能有助于以优雅的方式完成此任务。 see here for more details: https://www.npmjs.com/package/map-factory有关更多详细信息,请参见此处: https : //www.npmjs.com/package/map-factory
code will looks like this代码看起来像这样
const mapper = require("map-factory")();
mapper
.map("a")
.map("b.test.b1")
.map("c.d[].foo");
const input = {
a: 1,
b: {
test: {
b1: "b1"
}
},
c: {
d: [{ foo: 1 }, { foo: 2 }, { foo: 3, bar: 1 }, { bar: 12 }]
}
};
console.log(JSON.stringify(mapper.execute(input)));
Loadash alternative负载替代
Idk about loadash, but I would simply remove the []
from your string keys and use a simple function to retrieve what you are looking for. Idk 关于 loadash,但我会简单地从您的字符串键中删除
[]
并使用一个简单的函数来检索您要查找的内容。
const obj = { a: 1, b: { test: { b1: 'b1', }, }, c: { d: [{ foo: 1, }, { foo: 2, }, { foo: 3, bar: 1, }, { bar: 12, }], }, }; const myKeys = [ 'a', 'b.test.b1', 'cd[].foo', ].map(x => x.replace(/\\[\\]/, '')); function deepSearch(key, obj) { // We split the keys so we can loop on them const splittedKeys = key.split('.'); return splittedKeys.reduce((tmp, x, xi) => { if (tmp === void 0) { return tmp; } if (tmp instanceof Array) { const dataIndex = tmp.findIndex(y => y[x] !== void 0); // If the data we are looking for doesn't exists if (dataIndex === -1) { return void 0; } const data = tmp[dataIndex]; const ptr = data[x]; // Remove the data only if it's the last key we were looking for if (splittedKeys.length === xi + 1) { delete data[x]; // If the array element we removed the key from is now empty // remove it if (Object.keys(data).length === 0) { tmp.splice(dataIndex, 1); } } return ptr; } const ptr = tmp[x]; // Remove the data only if it's the last key we were looking for if (splittedKeys.length === xi + 1) { delete tmp[x]; } return ptr; }, obj); } console.log('Results', myKeys.map(x => deepSearch(x, obj))); console.log('Final object', obj);
I updated this answer to include a special function that I wrote that solves the problem.我更新了这个答案以包含我编写的解决问题的特殊函数。 I haven't tested it against every possible scenario, but I know with 100% certainty that it runs for your cases.
我没有针对所有可能的情况对其进行测试,但我 100% 确定它适用于您的情况。
_.mixin({ "pickSpecial": function pickSpecial(obj, key) { if (!_.includes(key, '[]')) { return _.pick(obj, key); } else { const keys = _.split(key, /(\\[\\]\\.|\\[\\])/); const pickFromArray = _.chain(obj) .get(_.first(keys)) .map((nextArrayElement) => pickSpecial(nextArrayElement, _.reduce(_.slice(keys, 2), (curr, next) => `${curr}${next}`, ''))) .compact() .reject((elem) => (_.isObject(elem) || _.isArray(elem)) && _.isEmpty(elem)) .value(); return _.chain(obj) .pick(_.first(keys)) .set(_.first(keys), pickFromArray) .value(); } } }); const initialData = { "a": 1, "b": {"test": { "b1": 'b1' }}, "c": { "d": [{foo: 1}, {foo: 2}, {foo: 3, bar: 1}, {bar: 12}] }, }; const keys = [ "a", "b.test.b1", "cd[].foo" ]; /* Expected result { "a": 1, "b": {"test": { "b1": 'b1' }}, "c": { "d": [{foo: 1}, {foo: 2}, {foo: 3}] }, } */ const output = _.chain(keys) .map((key) => _.pickSpecial(initialData, key)) .reduce((obj, next) => _.merge({}, obj, next), {}) .value(); console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.