简体   繁体   中英

Filter multidimensional array by key

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!

Update

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' },
]

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)); 

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); 

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) ); 

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); 

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); 

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 eg

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM