1

Question:

How can I removal all emailAddress that are empty, and if there are no emailAddresses for an approval, remove that approval too.

My current solution will remove approvals when emailAddress completely empty. But not when two emailAddresses are present and one is empty (see script output vs. expected output)

var request = {
 approvals: [
     {
       type: 'media',
       emailAddresses: [
        {emailAddress: '[email protected]'},
       ]
     },
     {
       type: 'other',
       emailAddresses: [
        {emailAddress: ''},
       ]
     },
     {
       type: 'scope',
       emailAddresses: [
        {emailAddress: '[email protected]'},
        {emailAddress: ''},
       ]
     }
   ] 
}
const filterOutEmptyEmails = (approval) => {
  if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
    return true;  
  }
  
}

let output = request.approvals.filter(filterOutEmptyEmails);

console.log(JSON.stringify(output));
 
 

// EXPECTED OUTPUT:
// approval: [
//     {
//       type: 'media',
//       emailAddresses: [
//         {emailAddress: '[email protected]'},
//       ]
//     },
//     {
//       type: 'scope',
//       emailAddresses: [
//         {emailAddress: '[email protected]'},
//       ]
//     }
//   ] 
// }]

Live Code

1
  • Your problem is this line: if(approval.emailAddresses.filter(x => !!x.emailAddress).length). You've told it to include the whole emailAddress array as long as it contains at least one non-empty email address. So I don't think you need to filter request.approvals, but rather loop over it and filter the emailAddress array for each one. Commented Nov 30, 2016 at 3:25

3 Answers 3

3

You are not replacing approval.emailAddresses in your code - you should use:

approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);

See demo below:

var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'[email protected]'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'[email protected]'},{emailAddress:''},]}]};
                        
var filterOutEmptyEmails = (approval) => {
   approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
  if(approval.emailAddresses.length){
    return true;  
  }
}

var output = request.approvals.filter(filterOutEmptyEmails);

console.log(JSON.stringify(output));

EDIT:

Another proposal without mutating the input array - using Array.prototype.reduce to create a new array:

var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'[email protected]'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'[email protected]'},{emailAddress:''},]}]};
                        

var output = request.approvals.reduce(function(p,c){
  // creates a shallow copy
  var elem = Object.assign({},c);
  // replaces the reference to request.approvals by the new array created by the filter
  elem.emailAddresses = elem.emailAddresses.filter(x => !!x.emailAddress);
  if(elem.emailAddresses.length != 0)
    p.push(elem);
  return p;
},[]);

// console.log(request.approvals);
console.log(output);
.as-console-wrapper{top:0;max-height:100%!important;}

Sign up to request clarification or add additional context in comments.

7 Comments

Ok so I see it works! Just a QQ: when filter returns true it will take account any mutations that happened inside of the loop?
Thats even more crazy cuz approval is a reference to the original object!
you want to do it without mutation?
Would it be possible to see that? I'm just practicing so that would be awesome!
The non-mutating version of this answer is better than my answer in regards of performance. See jsperf.com/fitering-nested-object-without-mutation
|
1

Possible "non mutation" solution could be like this

var request = {approvals: [{type: 'media',emailAddresses: [{emailAddress: '[email protected]'},]},{type: 'other',emailAddresses: [{emailAddress: ''},]},{type: 'scope', emailAddresses: [{emailAddress: '[email protected]'},{emailAddress: ''},]}]}

    const filterOutEmptyEmails = (approval) => {
      if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
        return true;  
      }
      
    }
       
    const output = request.approvals.map(approval => {
      const filteredAproval = approval;
      filteredAproval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
      return filteredAproval
    }).filter(filterOutEmptyEmails);
    

    console.log(JSON.stringify(output));
    console.log(JSON.stringify(request));

Comments

1

Without mutation (with lots of ES6/7 sugar):

const filteredApprovals = request.approvals.reduce((acc, approval) => {
  const filteredEmailAddresses = approval.emailAddresses.filter(item => item.emailAddress);
  return (filteredEmailAddresses.length > 0) ? [...acc, { ...approval, emailAddresses: filteredEmailAddresses }] : acc;
}, []);

Fiddle: https://jsfiddle.net/free_soul/hndjbce3/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.