如何匹配两个对象之间的值并创建具有特定值的新对象
How to match values between two objects and create new with specific values
我有对象数组 oDataSet
和 aProperties
对象,我想匹配在 aPropertis
中找到的 相同 值并在 oDataSet
中创建 aSelectedDataSet,在 beginning 中是一个空对象
在JS/Jquery
中推荐的做法
注意:loops/solution 中不应有任何 硬编码 属性 来进行匹配
aProperties 包含此值,但它可以更改(当然 oData 对象中应该有匹配...)
为澄清起见,以下是如何构建对象的示例
http://jsfiddle.net/4rh6tt25/5/
这是输入
//This is given array of object which can be many ,here I put just two instance in the array for demonstration purpose
var oDataSet = [{
__metadata: {
aaa: 111,
bbb: 222
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 1',
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692111',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 2',
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 3',
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb5',
__metadata: {}
}
]
}
}, {
//This is the second instance of the object with same keys but different values
__metadata: {
aaa: 333,
bbb: 444
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 6',
ListTypeGroup: 'ListTypeGroup6',
ListTypeGroupDescription: 'ListTypeGroupDescription 6',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692116',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 7',
ListTypeGroup: 'ListTypeGroup7',
ListTypeGroupDescription: 'ListTypeGroupDescription 7',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 8',
ListTypeGroup: 'ListTypeGroup8',
ListTypeGroupDescription: 'ListTypeGroupDescription 8',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb8',
__metadata: {}
}
]
}
}
];
//This is the values which I should search find in oDataSet
//The to_ListTypeGroupAssignment or other property which under the same structure
//should be with the following path but under the results which is the only
//hardcoded property
var aProperties = [
"to_ListTypeGroupAssignment/ListTypeGroup",
"to_ListTypeGroupAssignment/ListTypeGroupDescription"
]
这是输出
这是输出示例,应根据上面输入中的两个对象的合并构建
var aSelectedDataSet = [
{
__metadata: {
aaa: 111,
bbb: 222
},
to_ListTypeGroupAssignment: {
results: [
{
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1'
},
{
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
},
{
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
}
]
}
},
{
__metadata: {
aaa: 333,
bbb: 444
},
to_ListTypeGroupAssignment: {
results: [
{
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1'
},
{
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
},
{
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
}
]
}
}
]
只是为了从下面的评论中澄清:)
唯一可以硬编码的是results
。
没有 任何 属性 名称,如 ListTypeGroup 和 ListTypeGroupDescription
这应该是 generic 并从 aProperties
读取
您查看 oData 的结构应该如下所示
property(like -> to_ListTypeGroupAssignmen)
results(hardcoded & mandatory in every exist object)
properties(like ListTypeGroup& ListTypeGroupDescription with there values)
如果我需要说得更清楚,请告诉我如何,我应该添加哪些附加信息...这是在我尽可能多地更新问题之后...
您必须将 oDataSet 的每个 属性 与 aSelectedDataSet
的每个 属性 进行比较
var res=[];
for (var key1 in oDataSet){
for(var key2 in aSelectedDataSet ){
if(key1==key2){
res[key1]=oDataSet[key1];
}
}
}
编辑:
如果你像这样定义过滤器
var filter={
__metadata:'',
to_ListTypeGroupAssignment:{
results:[{
ListTypeGroup:'',
ListTypeGroupDescription:''
}]
}
}
并通过递归将其应用于数据
function recursiveValue(filter,data){
var res={};
for(var key in filter){
var val=data[key];
var p=filter[key];
if(val==='undefined') continue;
if(p===''){
res[key] = val;
}else if(Array.isArray(p)){
var tmp = [];
for(var i=0;i<val.length;i++){
tmp.push(recursiveValue(filter[key][0],val[i]));
}
res[key] = tmp;
}else if(typeof p=='object'){
res[key] = recursiveValue(filter[key],val);
}
}
return res;
}
喜欢
var results=[];
for(var i=0;i<oDataSet.length;i++){
results.push(recursiveValue(filter,oDataSet[i]));
}
你得到
console.log(results);
其中一个简短的解决方案是使用 lodash。它具有 _.assignInWith(object, sources, [customizer])
功能,使用它您将拥有以下功能:
var customizer = function(key) { return key in aPropertis }
var newSet = _.assignInWith({} , oDataSet, customizer)
但是,它仅适用于一级属性。
您可以使用 ES5 提供的函数式编程技术来解决这个问题。试试这个 fiddle:https://jsfiddle.net/yh39of1b/3/
var aProperties = [
"to_ListTypeGroupAssignment/ListTypeGroup",
"to_ListTypeGroupAssignment/ListTypeGroupDescription"
];
//maps the properties you wish to capture
var propertyList = aProperties.map(function(properties) {
return properties.split('/');
});
//reduces the oData array to the data you require
aSelectedDataSet = oData.reduce(function(existing,current){
var obj = {};
//each iteration of oData goes through each property group
//first at the parent property level
propertyList.forEach(function(property){
if (typeof obj[property[0]] === 'undefined') {
obj[property[0]] = {};
obj[property[0]].results = [];
}
if(current[property[0]]) {
//now at the child property level
current[property[0]].results.forEach(function(result,index){
if(typeof obj[property[0]].results[index] === 'undefined')
obj[property[0]].results[index] = {};
obj[property[0]].results[index][property[1]] = result[property[1]];
});
}
});
//add the newly mapped object to the aSelectedDataSet array
existing.push(obj);
return existing;
},[]);
不是最优雅的方式,但有效。
比较嵌套结构并删除不需要的键。
限制:
1. __metadata
是硬编码的
2. results
是硬编码的
您想要的输出与生成的不同,区别在于
你的输出:
aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 1
而在生成的输出中它是:
aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 6
我想,这是你问题中的错字。
代码:
var convertPropertyRelation = function(propertiesArray) {
if (!Array.isArray(propertiesArray))
return [];
var formattedProperties = {},
i, len = propertiesArray.length,
currentRelation;
for (i = 0; i < len; i++) {
currentRelation = propertiesArray[i].split('/');
if (formattedProperties.hasOwnProperty(currentRelation[0])) {
formattedProperties[currentRelation[0]].push(currentRelation[1]);
} else {
formattedProperties[currentRelation[0]] = [currentRelation[1]];
}
}
return formattedProperties;
};
var generateDataSet = function() {
var formattedProperties = convertPropertyRelation(aProperties),
firstRelation = Object.keys(formattedProperties),
i, len = firstRelation.length,
j, resultArray, resultLength;
var dataSet = oDataSet.map(function(dataSetObject) {
for (var firstKey in dataSetObject) {
if (firstKey === '__metadata') {
continue;
} else if (firstRelation.indexOf(firstKey) === -1) {
delete dataSetObject[firstKey];
} else {
// if first relation is present
if (dataSetObject.hasOwnProperty(firstKey)) {
// results array in the firstRelation
resultArray = dataSetObject[firstKey].results;
// for all results
for (j = 0, resultLength = resultArray.length; j < resultLength; j++) {
// for all keys in current result
for (var respectiveKey in resultArray[j]) {
// if the key is present leave it as it is
if (formattedProperties[firstKey].indexOf(respectiveKey) === -1) {
delete resultArray[j][respectiveKey];
}
}
}
}
}
}
return dataSetObject;
});
return dataSet;
};
您可以使用这个递归的纯 JavaScript 函数:
下面的代码片段将此函数应用于您提供的示例数据,returns 所需的结果:
function extract(data, select, curpath) {
var result = {};
// Part of the path that has been traversed to get to data:
curpath = curpath || '';
if (typeof data !== 'object') { // data is a primitive (we assume)
return data;
}
if (typeof data.slice === 'function') { // data is an Array
return data.map(function (el, idx) {
return extract(el, select, curpath); // same path!
});
}
// data is an Object:
// The specific case of the "__metadata" property
if (data.__metadata !== undefined && curpath.length === 0) {
result.__metadata = data.__metadata;
}
// Core of this algorithm: take the relevant paths only...
var subselect = select.filter(function(path) {
return (path+'/').indexOf(curpath) == 0;
});
subselect.forEach(function (path, _, subselect) {
// then get the next property in such path...
var prop = path.substr(curpath.length).split('/')[0];
// and check if we have that property on the current object:
if (data[prop] !== undefined) {
// If so, recurse while adding this to the current path:
result[prop] = extract(data[prop], subselect, curpath+prop+'/');
}
});
// The specific case of the "results" property
if (data.results !== undefined) { // recurse with same path!
result.results = extract(data.results, select, curpath);
}
return result;
}
// Test data
var oDataSet = [{
__metadata: {
aaa: 111,
bbb: 222
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 1',
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692111',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 2',
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 3',
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb5',
__metadata: {}
}
]
}
}, {
__metadata: {
aaa: 333,
bbb: 444
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 6',
ListTypeGroup: 'ListTypeGroup6',
ListTypeGroupDescription: 'ListTypeGroupDescription 6',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692116',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 7',
ListTypeGroup: 'ListTypeGroup7',
ListTypeGroupDescription: 'ListTypeGroupDescription 7',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 8',
ListTypeGroup: 'ListTypeGroup8',
ListTypeGroupDescription: 'ListTypeGroupDescription 8',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb8',
__metadata: {}
}
]
}
}
];
var aProperties = [
"to_ListTypeGroupAssignment/ListTypeGroup",
"to_ListTypeGroupAssignment/ListTypeGroupDescription"
];
// (End of sample data)
// Call the function to get the result:
var aSelectedDataSet = extract(oDataSet, aProperties);
// For this snippet only: output the result in readable format
document.write('<pre>'+JSON.stringify(aSelectedDataSet, 0, 4)+'</pre>');
算法说明:
代码已注释。算法是这样工作的:
- 该函数是递归的,获取当前数据,一旦函数被递归调用,当前数据将只是原始数据的一个子部分。
- 该函数还将路径样式属性设为 select。此外,由于递归调用该函数,此列表将更短,因此它仅包含那些仍然与数据部分相关的条目。
- 第三个参数是已经走过的路径。在最初的调用中,这只是一个空字符串,但是随着递归的开始,它将变成 'to_ListTypeGroupAssignment/',后来甚至是 'to_ListTypeGroupAssignment/ListTypeGroup/'(总是以斜线结尾)。
- 函数的每次调用都会 return 与(路径样式)selection 匹配的给定数据的一部分。
- 该函数首先识别数据的类型:它是原始值(字符串、数字、布尔值)还是数组(在初始调用时就是这种情况),还是(非-数组)对象。
- 如果它是一个数组,则只为每个元素递归调用该函数,而不向路径添加任何内容。然后将每次调用的结果存储在一个数组中,该数组成为 return 值。
- 如果是原始值,则表示我们递归到"tree"中的一个"leaf"。并且由于我们到达这里,我们可以假设 "path" 一直匹配到这一点,因此原始值必须 returned 以便可以将其添加到结果
- 如果是对象,则遍历select条路径,看这些路径中的下一层是否与当前数据的对象属性相匹配。如果是这样,该 属性 值将通过递归调用传递,同时还将那段路径添加到 "current" 路径
明显有__metadata
和results
的例外情况,在代码中分别处理。
我有对象数组 oDataSet
和 aProperties
对象,我想匹配在 aPropertis
中找到的 相同 值并在 oDataSet
中创建 aSelectedDataSet,在 beginning 中是一个空对象
在JS/Jquery
中推荐的做法注意:loops/solution 中不应有任何 硬编码 属性 来进行匹配 aProperties 包含此值,但它可以更改(当然 oData 对象中应该有匹配...)
为澄清起见,以下是如何构建对象的示例
http://jsfiddle.net/4rh6tt25/5/
这是输入
//This is given array of object which can be many ,here I put just two instance in the array for demonstration purpose
var oDataSet = [{
__metadata: {
aaa: 111,
bbb: 222
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 1',
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692111',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 2',
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 3',
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb5',
__metadata: {}
}
]
}
}, {
//This is the second instance of the object with same keys but different values
__metadata: {
aaa: 333,
bbb: 444
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 6',
ListTypeGroup: 'ListTypeGroup6',
ListTypeGroupDescription: 'ListTypeGroupDescription 6',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692116',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 7',
ListTypeGroup: 'ListTypeGroup7',
ListTypeGroupDescription: 'ListTypeGroupDescription 7',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 8',
ListTypeGroup: 'ListTypeGroup8',
ListTypeGroupDescription: 'ListTypeGroupDescription 8',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb8',
__metadata: {}
}
]
}
}
];
//This is the values which I should search find in oDataSet
//The to_ListTypeGroupAssignment or other property which under the same structure
//should be with the following path but under the results which is the only
//hardcoded property
var aProperties = [
"to_ListTypeGroupAssignment/ListTypeGroup",
"to_ListTypeGroupAssignment/ListTypeGroupDescription"
]
这是输出
这是输出示例,应根据上面输入中的两个对象的合并构建
var aSelectedDataSet = [
{
__metadata: {
aaa: 111,
bbb: 222
},
to_ListTypeGroupAssignment: {
results: [
{
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1'
},
{
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
},
{
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
}
]
}
},
{
__metadata: {
aaa: 333,
bbb: 444
},
to_ListTypeGroupAssignment: {
results: [
{
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1'
},
{
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
},
{
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
}
]
}
}
]
只是为了从下面的评论中澄清:)
唯一可以硬编码的是results
。
没有 任何 属性 名称,如 ListTypeGroup 和 ListTypeGroupDescription
这应该是 generic 并从 aProperties
您查看 oData 的结构应该如下所示
property(like -> to_ListTypeGroupAssignmen)
results(hardcoded & mandatory in every exist object)
properties(like ListTypeGroup& ListTypeGroupDescription with there values)
如果我需要说得更清楚,请告诉我如何,我应该添加哪些附加信息...这是在我尽可能多地更新问题之后...
您必须将 oDataSet 的每个 属性 与 aSelectedDataSet
的每个 属性 进行比较var res=[];
for (var key1 in oDataSet){
for(var key2 in aSelectedDataSet ){
if(key1==key2){
res[key1]=oDataSet[key1];
}
}
}
编辑:
如果你像这样定义过滤器
var filter={
__metadata:'',
to_ListTypeGroupAssignment:{
results:[{
ListTypeGroup:'',
ListTypeGroupDescription:''
}]
}
}
并通过递归将其应用于数据
function recursiveValue(filter,data){
var res={};
for(var key in filter){
var val=data[key];
var p=filter[key];
if(val==='undefined') continue;
if(p===''){
res[key] = val;
}else if(Array.isArray(p)){
var tmp = [];
for(var i=0;i<val.length;i++){
tmp.push(recursiveValue(filter[key][0],val[i]));
}
res[key] = tmp;
}else if(typeof p=='object'){
res[key] = recursiveValue(filter[key],val);
}
}
return res;
}
喜欢
var results=[];
for(var i=0;i<oDataSet.length;i++){
results.push(recursiveValue(filter,oDataSet[i]));
}
你得到
console.log(results);
其中一个简短的解决方案是使用 lodash。它具有 _.assignInWith(object, sources, [customizer])
功能,使用它您将拥有以下功能:
var customizer = function(key) { return key in aPropertis }
var newSet = _.assignInWith({} , oDataSet, customizer)
但是,它仅适用于一级属性。
您可以使用 ES5 提供的函数式编程技术来解决这个问题。试试这个 fiddle:https://jsfiddle.net/yh39of1b/3/
var aProperties = [
"to_ListTypeGroupAssignment/ListTypeGroup",
"to_ListTypeGroupAssignment/ListTypeGroupDescription"
];
//maps the properties you wish to capture
var propertyList = aProperties.map(function(properties) {
return properties.split('/');
});
//reduces the oData array to the data you require
aSelectedDataSet = oData.reduce(function(existing,current){
var obj = {};
//each iteration of oData goes through each property group
//first at the parent property level
propertyList.forEach(function(property){
if (typeof obj[property[0]] === 'undefined') {
obj[property[0]] = {};
obj[property[0]].results = [];
}
if(current[property[0]]) {
//now at the child property level
current[property[0]].results.forEach(function(result,index){
if(typeof obj[property[0]].results[index] === 'undefined')
obj[property[0]].results[index] = {};
obj[property[0]].results[index][property[1]] = result[property[1]];
});
}
});
//add the newly mapped object to the aSelectedDataSet array
existing.push(obj);
return existing;
},[]);
不是最优雅的方式,但有效。
比较嵌套结构并删除不需要的键。
限制:
1. __metadata
是硬编码的
2. results
是硬编码的
您想要的输出与生成的不同,区别在于 你的输出:
aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 1
而在生成的输出中它是:
aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 6
我想,这是你问题中的错字。
代码:
var convertPropertyRelation = function(propertiesArray) {
if (!Array.isArray(propertiesArray))
return [];
var formattedProperties = {},
i, len = propertiesArray.length,
currentRelation;
for (i = 0; i < len; i++) {
currentRelation = propertiesArray[i].split('/');
if (formattedProperties.hasOwnProperty(currentRelation[0])) {
formattedProperties[currentRelation[0]].push(currentRelation[1]);
} else {
formattedProperties[currentRelation[0]] = [currentRelation[1]];
}
}
return formattedProperties;
};
var generateDataSet = function() {
var formattedProperties = convertPropertyRelation(aProperties),
firstRelation = Object.keys(formattedProperties),
i, len = firstRelation.length,
j, resultArray, resultLength;
var dataSet = oDataSet.map(function(dataSetObject) {
for (var firstKey in dataSetObject) {
if (firstKey === '__metadata') {
continue;
} else if (firstRelation.indexOf(firstKey) === -1) {
delete dataSetObject[firstKey];
} else {
// if first relation is present
if (dataSetObject.hasOwnProperty(firstKey)) {
// results array in the firstRelation
resultArray = dataSetObject[firstKey].results;
// for all results
for (j = 0, resultLength = resultArray.length; j < resultLength; j++) {
// for all keys in current result
for (var respectiveKey in resultArray[j]) {
// if the key is present leave it as it is
if (formattedProperties[firstKey].indexOf(respectiveKey) === -1) {
delete resultArray[j][respectiveKey];
}
}
}
}
}
}
return dataSetObject;
});
return dataSet;
};
您可以使用这个递归的纯 JavaScript 函数:
下面的代码片段将此函数应用于您提供的示例数据,returns 所需的结果:
function extract(data, select, curpath) {
var result = {};
// Part of the path that has been traversed to get to data:
curpath = curpath || '';
if (typeof data !== 'object') { // data is a primitive (we assume)
return data;
}
if (typeof data.slice === 'function') { // data is an Array
return data.map(function (el, idx) {
return extract(el, select, curpath); // same path!
});
}
// data is an Object:
// The specific case of the "__metadata" property
if (data.__metadata !== undefined && curpath.length === 0) {
result.__metadata = data.__metadata;
}
// Core of this algorithm: take the relevant paths only...
var subselect = select.filter(function(path) {
return (path+'/').indexOf(curpath) == 0;
});
subselect.forEach(function (path, _, subselect) {
// then get the next property in such path...
var prop = path.substr(curpath.length).split('/')[0];
// and check if we have that property on the current object:
if (data[prop] !== undefined) {
// If so, recurse while adding this to the current path:
result[prop] = extract(data[prop], subselect, curpath+prop+'/');
}
});
// The specific case of the "results" property
if (data.results !== undefined) { // recurse with same path!
result.results = extract(data.results, select, curpath);
}
return result;
}
// Test data
var oDataSet = [{
__metadata: {
aaa: 111,
bbb: 222
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 1',
ListTypeGroup: 'ListTypeGroup1',
ListTypeGroupDescription: 'ListTypeGroupDescription 1',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692111',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 2',
ListTypeGroup: 'ListTypeGroup2',
ListTypeGroupDescription: 'ListTypeGroupDescription 2',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 3',
ListTypeGroup: 'ListTypeGroup3',
ListTypeGroupDescription: 'ListTypeGroupDescription 3',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb5',
__metadata: {}
}
]
}
}, {
__metadata: {
aaa: 333,
bbb: 444
},
to_ExcludedTerms: {results: []},
to_ListTypeGroupAssignment: {
results: [
{
AuthorisationGroup: 'AuthorisationGroup 6',
ListTypeGroup: 'ListTypeGroup6',
ListTypeGroupDescription: 'ListTypeGroupDescription 6',
ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692116',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 7',
ListTypeGroup: 'ListTypeGroup7',
ListTypeGroupDescription: 'ListTypeGroupDescription 7',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
__metadata: {}
},
{
AuthorisationGroup: 'AuthorisationGroup 8',
ListTypeGroup: 'ListTypeGroup8',
ListTypeGroupDescription: 'ListTypeGroupDescription 8',
ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb8',
__metadata: {}
}
]
}
}
];
var aProperties = [
"to_ListTypeGroupAssignment/ListTypeGroup",
"to_ListTypeGroupAssignment/ListTypeGroupDescription"
];
// (End of sample data)
// Call the function to get the result:
var aSelectedDataSet = extract(oDataSet, aProperties);
// For this snippet only: output the result in readable format
document.write('<pre>'+JSON.stringify(aSelectedDataSet, 0, 4)+'</pre>');
算法说明:
代码已注释。算法是这样工作的:
- 该函数是递归的,获取当前数据,一旦函数被递归调用,当前数据将只是原始数据的一个子部分。
- 该函数还将路径样式属性设为 select。此外,由于递归调用该函数,此列表将更短,因此它仅包含那些仍然与数据部分相关的条目。
- 第三个参数是已经走过的路径。在最初的调用中,这只是一个空字符串,但是随着递归的开始,它将变成 'to_ListTypeGroupAssignment/',后来甚至是 'to_ListTypeGroupAssignment/ListTypeGroup/'(总是以斜线结尾)。
- 函数的每次调用都会 return 与(路径样式)selection 匹配的给定数据的一部分。
- 该函数首先识别数据的类型:它是原始值(字符串、数字、布尔值)还是数组(在初始调用时就是这种情况),还是(非-数组)对象。
- 如果它是一个数组,则只为每个元素递归调用该函数,而不向路径添加任何内容。然后将每次调用的结果存储在一个数组中,该数组成为 return 值。
- 如果是原始值,则表示我们递归到"tree"中的一个"leaf"。并且由于我们到达这里,我们可以假设 "path" 一直匹配到这一点,因此原始值必须 returned 以便可以将其添加到结果
- 如果是对象,则遍历select条路径,看这些路径中的下一层是否与当前数据的对象属性相匹配。如果是这样,该 属性 值将通过递归调用传递,同时还将那段路径添加到 "current" 路径
明显有__metadata
和results
的例外情况,在代码中分别处理。