如何根据给定的部分路径过滤对象?
作为一个例子。
let address = {
country :{
name:'Japan',
city:{
name:'Tokyo',
town: {
name:'korushawa'
}
},
code:'JP'
},
nearbyCountry:'Korea'
}
路径1: countr.cit
对于address
,路径1将导致
{
country :{
city:{
name:'Tokyo',
town: {
name:'korushawa'
}
}
}
}
对于路径2,
我应该获取整个address
对象,因为 counter 存在于country
和nearbyCountry
{
country :{
name:'Japan',
city:{
name:'Tokyo',
town: {
name:'korushawa'
}
}
},
nearbyCountry:'Korea'
}
编辑:给定确切的路径(例如:country.city
),我已经能够解决此问题。但是在局部路径上有困难。
答案 0 :(得分:4)
filter
使用include
该路径的键reduce
从键创建对象
obj
的所有过滤后的属性添加到累加器
const address={country:{name:'Japan',city:{name:'Tokyo',town:{name:'korushawa'}},code:'JP'},nearbyCountry:'Korea'};
function filterObject(obj, paths) {
if (!obj) return null;
const partial = paths.shift(),
filteredKeys = Object.keys(obj).filter(k => k.toLowerCase().includes(partial));
if (!filteredKeys.length) return null; // no keys with the path found
return filteredKeys.reduce((acc, key) => {
if(!paths.length) return { ...acc, [key]: obj[key] }
const nest = filterObject(obj[key], [...paths]) // filter another level
return nest ? { ...acc, [key]: nest } : acc
}, null)
}
let path;
console.log(path = 'countr', ':');
console.log(filterObject(address, path.split('.')))
console.log(path = 'countr.cit', ':');
console.log(filterObject(address, path.split('.')))
console.log(path = 'countr.cit.to', ':');
console.log(filterObject(address, path.split('.')))
console.log(path = 'countr.cit.doesntexist', ':');
console.log(filterObject(address, path.split('.')))
.as-console-wrapper {max-height:100% !important; top:0;}
如果只需要第一个与密钥完全或部分匹配的密钥,则可以拆分path
并像这样使用reduce
。如果找到了键,则返回对象,否则找到include
给定键的键(这提供了最后一个键匹配的数据。不是整个对象树)
const address={country:{name:'Japan',city:{name:'Tokyo',town:{name:'korushawa'}},code:'JP'},nearbyCountry:'Korea'},
path = "countr.cit";
const output = path.split('.').reduce((obj, key) => {
if (key in obj) {
return obj[key];
} else {
let found = Object.keys(obj).find(k => k.includes(key));
if (found)
return obj[found]
else
return {}
}
}, address);
console.log(output)
答案 1 :(得分:4)
由于我不完全了解您的目标(例如:为什么在第一个输出示例中,您保留name
对象的country
属性而不是code
属性),我会给您两种方法,希望对您有帮助。
在第一种方法中,我们递归遍历主要对象以过滤出在特定级别不匹配的keys
。输出将是object
,其属性在特定级别上匹配:
let address = {
country: {
name: 'Japan',
city: {name: 'Tokyo', town: {name: 'korushawa'}},
code: 'JP'
},
nearbyCountry: {name: 'Korea', code: 'KO'}
};
const myFilter = (obj, keys) =>
{
if (keys.length <= 0)
return obj;
return Object.keys(obj).reduce(
(nObj, k) => k.toLowerCase().match(keys[0])
? ({...nObj, [k]: myFilter(obj[k], keys.slice(1))})
: nObj,
{}
);
}
const customFilter = (o, k) => myFilter(
JSON.parse(JSON.stringify(o)),
k.split(".").map(x => x.toLowerCase())
);
console.log("Filter by 'countr':", customFilter(address, "countr"));
console.log("Filter by 'countr.cit':", customFilter(address, "countr.cit"));
console.log("Filter by 'countr.cit.to':", customFilter(address, "countr.cit.to"));
console.log("Filter by 'countr.cit.lala':", customFilter(address, "countr.cit.lala"));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
如您所见,当通过"countr.cit"
进行过滤时,即使内部key = nearbyCountry
与key
不匹配,这种方法也会保留cit
。 / p>
在这种方法中,我们将过滤掉主first-level keys
中所有object
的所有部分都不匹配的path
。但是,我不得不说这种方法有点奇怪。我相信,如果您的输入是一个对象数组,而不仅仅是一个对象,那么这样会更有意义。
let address = {
country: {
name: 'Japan',
city: {name: 'Tokyo', town: {name: 'korushawa'}},
code: 'JP'
},
nearbyCountry: {name: 'Korea', code: 'KO'}
};
const myFilter = (obj, paths) =>
{
let newObj = {};
Object.entries(obj).forEach(([key, val]) =>
{
let res = paths.slice(1).reduce((o, cp) =>
{
if (o === undefined) return o;
let found = Object.keys(o).find(k => k.toLowerCase().match(cp));
return found !== undefined ? o[found] : found;
}, val);
if (key.toLowerCase().match(paths[0]) && res !== undefined)
newObj[key] = val;
});
return newObj;
}
const customFilter = (o, k) => myFilter(
JSON.parse(JSON.stringify(o)),
k.split(".").map(x => x.toLowerCase())
);
console.log("Filter by 'countr':", customFilter(address, "countr"));
console.log("Filter by 'countr.cit':", customFilter(address, "countr.cit"));
console.log("Filter by 'countr.cit.to':", customFilter(address, "countr.cit.to"));
console.log("Filter by 'countr.cit.lala':", customFilter(address, "countr.cit.lala"));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
最后, @adiga 提供的答案中已经显示了您可能想要做的另一件事。
答案 2 :(得分:4)
这种方法依赖于过滤条目并通过映射具有单个属性的对象来重建新对象。
function getParts(object, fragments) {
var [part, ...rest] = fragments.split('.');
return Object.assign({}, ...Object
.entries(object)
.filter(([key]) => key.toLowerCase().includes(part))
.map(([k, v]) => {
if (!rest.length) return { [k]: v };
var parts = v && typeof v === 'object' && getParts(v, rest.join('.'));
if (parts) return { [k]: parts };
})
);
}
let address = { country: { name: 'Japan', city: { name: 'Tokyo', town: { name: 'korushawa' } }, code: 'JP' }, nearbyCountry: 'Korea' };
console.log(getParts(address, 'countr.cit'));
console.log(getParts(address, 'countr'));
.as-console-wrapper { max-height: 100% !important; top: 0; }