I've array of objects oDataSet
and aProperties
object and I want to match the identical values that are found in aPropertis
and and In oDataSet
and create the aSelectedDataSet which in beginning is an empty object
How it's recommend to do it in JS/Jquery
Note: there shouldnt be any hardcoded property in the loops/solution to do the match the aProperties is contain this value but it can be change (and of course there should be match in the oData object...)
For clarification Following is example how the objects is built
http://jsfiddle.net/4rh6tt25/5/
This is the input
//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"
]
This is the output
This is example of the output which should be build from the merge of both objects in the input above
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',
}
]
}
}
]
just to clarify from the comments below :)
The only thing that can be hard-coded is the results
.
Not any property name like ListTypeGroup& ListTypeGroupDescription
This should be generic and read from aProperties
The structure of you look at the oData should be like following
property(like -> to_ListTypeGroupAssignmen)
results(hardcoded & mandatory in every exist object)
properties(like ListTypeGroup& ListTypeGroupDescription with there values)
If I need to make it more clear please let me know How,which additional info I should add...This is after I update the question as much as possible...
-
5Can you please replace the image with code? It is much easier for people to try and reconstruct your issue copying and pasting code, rather than reading it from an image. See How to Ask.Tushar– Tushar2016年03月17日 14:02:38 +00:00Commented Mar 17, 2016 at 14:02
-
4Part of learning to program is to program stuff yourself. How about you try to apply that related question to your own code, then ask a specific question regarding where you're having an issue?Heretic Monkey– Heretic Monkey2016年03月17日 14:36:56 +00:00Commented Mar 17, 2016 at 14:36
-
2@MiltoxBeyond - only results can be hardcoded :) forgat to mention this07_05_GuyT– 07_05_GuyT2016年03月20日 17:26:41 +00:00Commented Mar 20, 2016 at 17:26
-
4@Frederik.L - Thanks but I think you missed the point here...most of the comments was to the original question which I update today dramtically and create JsFiddle , The output should be aSelectedDataSet I put and example how it should be created(with the values),in addition at the bottom of the fiddle you can see what I try ,without success :(07_05_GuyT– 07_05_GuyT2016年03月20日 19:27:54 +00:00Commented Mar 20, 2016 at 19:27
-
2I'm sorry but I must insist: you keep poorly asking what's your need, so even with good will nobody can really understand it. You seem to be always hurried, and it's not the good way to reach your goal. So please take the time to refactor your question in a clear way! Otherwise the time you're looking to save will be actually lost for you (because you'll not get any answer)... and for us!cFreed– cFreed2016年03月20日 22:34:35 +00:00Commented Mar 20, 2016 at 22:34
5 Answers 5
You could use this recursive, pure JavaScript function:
The snippet below applies this function to the example data you provided and returns the required result:
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>');
Explanation of the algorithm:
The code is commented. This is how the algorithm works:
- The function is recursive and takes the current data, which will be just a sub section of the original data once the function is called recursively.
- The function also takes the path-style properties to select. Also this list will be shorter as the function is called recursively, so it only has those entries that are still relevant to the data section.
- The third argument is the path that has already been traversed. At the initial call this is just the empty string, but as the recursion kicks in, it will become 'to_ListTypeGroupAssignment/', and later even 'to_ListTypeGroupAssignment/ListTypeGroup/' (always with terminating slash).
- Each call of the function will return a part of the given data that matches the (path-style) selection.
- The function starts by identifying the type of the data: whether it is a primitive value (a string, number, boolean), or an array (which is the case at the initial call), or an (non-array) object.
- If it is an array, the function is just called recursively for each element without adding anything to the path. The result of each call is then stored in an array, which becomes the return value.
- If it is a primitive value, it means we recursed to a "leaf" in the "tree". And since we got here, we may assume the "path" was matching up until this point, and so the primitive value must be returned so it can be added to the result
- It it is an object, the select paths are traversed to see if the next level in those paths matches with an object property of the current data. If so, that property value is passed via a recursive call, while also adding that piece of the path to the "current" path
There are obviously the exceptions for __metadata
and results
, which are treated separately in the code.
-
This should be the accepted answer IMO. Unless there is some other exceptions?Frederik.L– Frederik.L2016年03月22日 00:08:46 +00:00Commented Mar 22, 2016 at 0:08
One of the short solutions will be with lodash. It has _.assignInWith(object, sources, [customizer])
function, using that you are going have the following:
var customizer = function(key) { return key in aPropertis }
var newSet = _.assignInWith({} , oDataSet, customizer)
However it is going to work only for first level properties.
-
Sorry but I cannot use lodash.07_05_GuyT– 07_05_GuyT2016年03月21日 16:03:28 +00:00Commented Mar 21, 2016 at 16:03
-
In our project we cannot use lodash or undercore :(07_05_GuyT– 07_05_GuyT2016年03月21日 16:40:25 +00:00Commented Mar 21, 2016 at 16:40
-
1may i ask why? how you guys even working without it.vittore– vittore2016年03月21日 16:42:27 +00:00Commented Mar 21, 2016 at 16:42
-
I know that there are very good but in our project currently we cannot (legal etc )use lodash now but in the future we will ...07_05_GuyT– 07_05_GuyT2016年03月21日 17:09:16 +00:00Commented Mar 21, 2016 at 17:09
Not the most elegant way, but works.
Compared nested structure and removed the keys which were not required.
Limitations:
1. __metadata
is hardcoded
2. results
is hardcoded
Your desired output is different then what is generated, difference is Your output:
aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 1
Whereas in the generated output it is:
aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 6
I think, it was a typo in your question.
Code:
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;
};
-
Please post the code itself in your answer, not a link to it.Bergi– Bergi2016年03月21日 19:18:01 +00:00Commented Mar 21, 2016 at 19:18
-
@Bergi I have added the code, but the answer added by Trincot, is more elegant and betterBhavik– Bhavik2016年03月21日 19:35:17 +00:00Commented Mar 21, 2016 at 19:35
You will have to compare each property of oDataSet to each property of aSelectedDataSet
var res=[];
for (var key1 in oDataSet){
for(var key2 in aSelectedDataSet ){
if(key1==key2){
res[key1]=oDataSet[key1];
}
}
}
EDIT:
If you define filter like so
var filter={
__metadata:'',
to_ListTypeGroupAssignment:{
results:[{
ListTypeGroup:'',
ListTypeGroupDescription:''
}]
}
}
and apply it to data with recursion
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;
}
like so
var results=[];
for(var i=0;i<oDataSet.length;i++){
results.push(recursiveValue(filter,oDataSet[i]));
}
you get
console.log(results);
-
I try it but its not working,can you please use the jsFiddle which I provide? You dont refer to the results property, please use the code and I provide the exact output...07_05_GuyT– 07_05_GuyT2016年03月21日 16:41:43 +00:00Commented Mar 21, 2016 at 16:41
-
You code will not work(its not that simple...) since the aSelectedDataSet is just a var and its empty after the match it should be filled(like the output in the question...)07_05_GuyT– 07_05_GuyT2016年03月21日 17:10:52 +00:00Commented Mar 21, 2016 at 17:10
You could tackle this using functional programming techiniques made available by ES5. Try this 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;
},[]);
Explore related questions
See similar questions with these tags.