遍历基于对象的属性路径数组



Hi我需要帮助迭代SubjectViewModel,并检查formfieldkeyPath的路径是否与数组中每个对象的PropertyKey匹配,如果propery路径值为null,则仅返回true。

例如formfieldkeyPath,它是一个值为department.subjectCost的字符串

export class SubjectViewModel {
public id?: number;
public SubjectInfo?: string;
public studentId?: number;
public department?:DepartmentViewModel;
public studentBenefits?: studentBenefitViewModel[];

}
export class DepartmentViewModel{
public id?: number;
public departmentName?:string;
public subjectCost?:number;
public departmentBenefits?: departmentBenefitViewModel[];

}
SubjectViewModel =[
{
id:4,
SubjectInfo:'xx',
studentId:16,
department:[
{
id:1,
departmentName:'xxx',
subjectCost:null,
departmentBenefits:[{..},{..}]
},
{
id:2,
departmentName:'yyy',
subjectCost:50,
departmentBenefits:[{..},{..}]
}],
studentBenefits:[{..},{..}]
}
]

i split the department.subjectCost into an array
const propertyPathArr = formfieldkeyPath .split('.'),

我也不得不这样做过几次。你已经很接近按周期拆分了。从这里开始,您只需要使用括号表示法迭代到由该字符串确定的每个深度级别,然后使用map()返回匹配属性值的新数组。

在您试图检索的数据和您想要使用的formfieldkeyPath(department.subjectCost(之间,我看到的唯一复杂情况是department是您想要迭代的区域,而subjectCost是我们想要通过map()收集的数据。这将留下关于哪个属性路径"的一些模糊性;部分";是要迭代的数组,以及在循环遍历该数组时要收集的数据。

为了解决这个问题,我们需要使用一个稍微不同的符号来分隔这两个部分,即要循环通过的数组的路径和要在该数组中收集的属性的路径。从本质上讲,我们将构建两个用路径名填充的嵌套数组,然后循环使用这些属性路径名来获得所需的数据。

例如,如果您的对象嵌套在另外两个对象objsubobj中,我们可以将obj.subobj.department->subjectCost转换为[['obj','subobj','department'],['subjectCost']]。因此,为了使其适用于更简单的示例,我们将只使用department->subjectCost,因为我们需要为具有更高复杂性的对象保存.字符。

**这里的另一个重要注意事项是,因为我们将使用符号.->来分割字符串,这将与任何在其属性名称中实际包含这些确切字符串的对象键相冲突,所以要小心。如果您的属性的名称中有任何一个符号,只需更改下面我提供的函数中使用的符号即可。也许您可以使用.....来代替.->,其中两个点可以表示一条路径(向下一级(,三个点表示阵列的路径和您正在收集的所需数据的路径之间的分割。在我们的情况下,它将是department...subjectCost

示例1:使用您提供的样本数据

在这里,它使用您提供的样本数据(.->(对department->subjectCost起作用:

用法

iterPropPath(SubjectViewModel[0], 'department->subjectCost');
// -> [null, 50]

完整示例

const SubjectViewModel = [{
id: 4,
SubjectInfo: 'xx',
studentId: 16,
department: [{
id: 1,
departmentName: 'xxx',
subjectCost: null,
departmentBenefits: [{/**/}, {/**/}]
}, {
id: 2,
departmentName: 'yyy',
subjectCost: 50,
departmentBenefits: [{/**/}, {/**/}]
}],
studentBenefits: [{/**/}, {/**/}]
}];
const iterPropPath = (obj, path) => {
path = path.replace(/[(w+)]/g, '.$1').replace(/^./, '');
const pathArray = path.split('->').map(e => e.split('.').filter(f => f)).filter(e => e && e.length);
if (pathArray.length !== 2) {
console.error('iterPropPath requires a valid object path to a nested array and a valid path within that array to the desired property value. Property path levels should be delimited by `.` and the array path/property path should be delimited by `->`.');
return false;
}
const [arrPath, propPath] = pathArray;
let arr = obj;
let arrPathValid = true;
arrPath.slice().forEach(step => arr.hasOwnProperty(step) ? (arr = arr[arrPath.shift(1)], !arrPath.length && (!Array.isArray(arr) || !arr.length) && (arrPathValid = false)) : (arrPathValid = false));
if (!arrPathValid) {
console.error(`Array path ${arrPath.join('.')} is invalid.`);
return false;
}
return arr.map((e,iPropPath) => (iPropPath = propPath.slice(), propPath.forEach(step => e && e.hasOwnProperty(step) && (e = e[iPropPath.shift(1)])), e));
};
const formfieldkeyPath = 'department->subjectCost';
const subjectCosts = iterPropPath(SubjectViewModel[0], formfieldkeyPath);
console.log(subjectCosts);

这跟随所提供的对象SubjectViewModel[0]的路径,沿着指定的路径到达数组,然后遍历数组,返回所需值的新映射数组,在这种情况下为[null, 50](subjectCost值(。

示例2:更复杂的示例

下面是这个函数的一个更深层次的例子,它使用了括号表示法。为了支持括号表示法,我添加了几个replace语句,这些语句的灵感来自@Alnitak在2011年对一个相关问题的回答:

用法

iterPropPath(deepArray, 'entries.data->a[1].names[2]');
// -> ["Ron", "Eli", "Bre"]

完整示例

const deepArray = {
id: 0,
entries: {
randomData: true,
data: [
{ a: ['test1-1', { names: [ 'Tom', 'Kim', 'Ron' ] }], b: [['test1-2'], ['test1-3']]},
{ a: ['test2-1', { names: [ 'Jim', 'Lia', 'Eli' ] }], b: [['test2-2'], ['test2-3']]},
{ a: ['test3-1', { names: [ 'Tia', 'Jon', 'Bre' ] }], b: [['test3-2'], ['test3-3']]}
]
}
};
const iterPropPath = (obj, path) => {
path = path.replace(/[(w+)]/g, '.$1').replace(/^./, '');
const pathArray = path.split('->').map(e => e.split('.').filter(f => f)).filter(e => e && e.length);
if (pathArray.length !== 2) {
console.error('iterPropPath requires a valid object path to a nested array and a valid path within that array to the desired property value. Property path levels should be delimited by `.` and the array path/property path should be delimited by `->`.');
return false;
}
const [arrPath, propPath] = pathArray;
let arr = obj;
let arrPathValid = true;
arrPath.slice().forEach(step => arr.hasOwnProperty(step) ? (arr = arr[arrPath.shift(1)], !arrPath.length && (!Array.isArray(arr) || !arr.length) && (arrPathValid = false)) : (arrPathValid = false));
if (!arrPathValid) {
console.error(`Array path ${arrPath.join('.')} is invalid.`);
return false;
}
return arr.map((e,iPropPath) => (iPropPath = propPath.slice(), propPath.forEach(step => e && e.hasOwnProperty(step) && (e = e[iPropPath.shift(1)])), e));
};
const path = 'entries.data->a[1].names[2]';
const namesFromDeepArray = iterPropPath(deepArray, path);
console.log(namesFromDeepArray);

最新更新