Reputation: 1185
I've looked into using reduce, filter, and map in other examples I've seen on SO, but I'm not sure if they fit my use-case. Say I have the following multidimensional array:
const variableOpts = [
{ id: -1, value: 'Select Variable' },
{ id: 1,
value: 'Patient',
options: [
{ id: 2, value: 'First Name', variable: '{first_name}', variableValue: 'Billy' },
{ id: 3, value: 'Last Name', variable: '{last_name}', variableValue: 'Bob' },
{ id: 4, value: 'Office Location', variable: '{office_location}', variableValue: 'Mount Pleasant' },
],
},
{ id: 5, value: 'Another option', variable: '{another_option}', variableValue: 'Test' },
];
What I'd like to do is grab any objects that contain the variable
key, whether they are a top-level item, or within an item; like the options
array holds. Any help would be greatly appreciated. Thanks!
Ideally I'd like to have an array with everything at one-level so I can loop over them, like this:
[
{ id: 2, value: 'First Name', variable: '{first_name}', variableValue: 'Billy' },
{ id: 3, value: 'Last Name', variable: '{last_name}', variableValue: 'Bob' },
{ id: 4, value: 'Office Location', variable: '{office_location}', variableValue: 'Mount Pleasant' },
{ id: 5, value: 'Another option', variable: '{another_option}', variableValue: 'Test' },
]
Upvotes: 0
Views: 576
Reputation: 1055
You can do something short and strait forward.
const variableOpts = [{ id: -1, value: 'Select Variable'},{id: 1,value: 'Patient',options: [{id: 2,value:'First Name', variable: '{first_name}',variableValue: 'Billy'},{id: 3,value: 'Last Name',variable: '{last_name}',ariableValue: 'Bob'},{ id: 4, value: 'Office Location',variable: '{office_location}',variableValue: 'Mount Pleasant'},],},{id: 5,value: 'Another option',variable: '{another_option}',variableValue: 'Test'},];
var val = variableOpts.filter(item => item.id != -1)
val = val.reduce((a, b) => a.concat(b.options || b), [])
console.log(val);
Upvotes: 1
Reputation: 3241
I'm not sure I really like my answer, but it seems to work.
const variableOpts = [{ id: -1, value: 'Select Variable' }, { id: 1, value: 'Patient', options: [{ id: 2, value: 'First Name', variable: '{first_name}', variableValue: 'Billy' }, { id: 3, value: 'Last Name', variable: '{last_name}', variableValue: 'Bob' }, { id: 4, value: 'Office Location', variable: '{office_location}', variableValue: 'Mount Pleasant' },], }, { id: 5, value: 'Another option', variable: '{another_option}', variableValue: 'Test' },];
let result = [];
let checkArrayEntry = obj => {
if (obj.hasOwnProperty('variable')) result.push(obj);
Object.keys(obj).filter(prop => obj[prop] instanceof Array).forEach(entry => obj[entry].forEach(checkArrayEntry));
};
variableOpts.forEach(checkArrayEntry);
console.log(result);
Upvotes: 1
Reputation: 8139
If you want a functional solution using map you could first define a flatten function
function flatten(arr) {
return [].concat.apply([], arr)
}
function filterArray(arr, f) {
if(!(arr instanceof Array)) return [];
return flatten(arr.map(elem =>
(f(elem)?[elem]:[]).concat(filterArray(elem["options"], f))
));
}
Then you can write e.g.
console.log(filterArray(variableOpts, elem => elem["variable"]&&elem["variable"].indexOf("name")>=0));
To get all elements that have the string name
somewhere in their variable
property.
Upvotes: 0
Reputation: 4475
You can first filter the objects that either have the options
or variable
keys, then normalize the results in a for
loop…
const variableOpts = [{id: -1, value: 'Select Variable' }, {id: 1, value: 'Patient', options: [{id: 2, value: 'First Name', variable: '{first_name}', variableValue: 'Billy' }, {id: 3, value: 'Last Name', variable: '{last_name}', variableValue: 'Bob' }, {id: 4, value: 'Office Location', variable: '{office_location}', variableValue: 'Mount Pleasant' }]}, {id: 5, value: 'Another option', variable: '{another_option}', variableValue: 'Test' }];
const tempOpts = variableOpts.filter(function(obj){
return (obj.options && Array.isArray(obj.options)) || obj.variable;
});
const finalOpts = [];
for(let i = 0; i < tempOpts.length; i++){
let currentOpt = tempOpts[i];
if(currentOpt.options)
{
for(let i = 0; i < currentOpt.options.length; i++){
finalOpts.push(currentOpt.options[i]);
}
}else
{
finalOpts.push(currentOpt);
}
}
console.log(finalOpts);
Upvotes: 2
Reputation: 15301
Using recursion, you can loop over the array, check each value for the key variable
and if found append it to an array of good values. Then check if there is an options key, if found, recurse to check each option. Something like this:
const variableOpts = [{ id: -1, value: 'Select Variable' }, { id: 1, value: 'Patient', options: [{ id: 2, value: 'First Name', variable: '{first_name}', variableValue: 'Billy' }, { id: 3, value: 'Last Name', variable: '{last_name}', variableValue: 'Bob' }, { id: 4, value: 'Office Location', variable: '{office_location}', variableValue: 'Mount Pleasant' }, ], }, { id: 5, value: 'Another option', variable: '{another_option}', variableValue: 'Test' }, ];
function findVariable(arr){
//output variable
var out = [];
//loop over array
arr.forEach(function(a){
//if has variable key, add it to output
if(a.variable){
out.push(a);
}
//if has options, recurse and concat any with variable to output
if(Array.isArray(a.options)){
out = out.concat(findVariable(a.options));
}
});
//return the output
return out;
}
console.log(findVariable(variableOpts));
Upvotes: 2
Reputation: 4365
You can do a recursive check while populating your resulting array:
const variableOpts=[{id:-1,value:'Select Variable'},{id:1,value:'Patient',options:[{id:2,value:'First Name',variable:'{first_name}',variableValue:'Billy'},{id:3,value:'Last Name',variable:'{last_name}',variableValue:'Bob'},{id:4,value:'Office Location',variable:'{office_location}',variableValue:'Mount Pleasant'}]},{id:5,value:'Another option',variable:'{another_option}',variableValue:'Test'}];
var findObjects = function() {
var isArray = function(a) {
return a.map == [].map;
};
var isObject = function(o) {
return Object(o) === o;
};
var result = [];
var stepThrough = function(obj) {
if (isArray(obj))
return obj.forEach(stepThrough);
if (isObject(obj)) {
for (var key in obj)
if (isArray(obj[key])) {
stepThrough(obj[key]);
delete obj[key];
}
if (obj.hasOwnProperty('variable'))
result.push(obj);
}
};
for (var i = 0; i < arguments.length; i++) {
stepThrough(arguments);
}
return result;
};
console.log( findObjects(variableOpts) );
Upvotes: 1