1

I have a javascript array like so:

var recipients = [{
  name: 'Michael',
  task: 'programming',
  contactdetails: '[email protected]'
}, {
  name: 'Michael',
  task: 'designing',
  contactdetails: '[email protected]'
}, {
  name: 'Shane',
  task: 'designing',
  contactdetails: '[email protected]'
}];

What I am doing is a rostering system where I send out notifications for who is on for this week, so the email is like "Hi Michael you are programming this week". At the moment it is not great because it sends out an email for every value in the array. So in the above instance it would send Michael 2 emails.

What I would like to do is remove duplicates while merging the task property strings. So the array would be:

var recipients = [{
  name: 'Michael',
  task: 'programming, designing',
  contactdetails: '[email protected]'
}, {
  name: 'Shane',
  task: 'designing',
  contactdetails: '[email protected]'
}];

that way it can just send one message like "Hi Michael you are programming, designing this week". How do I go about this? I also am using Google Apps script so I need a pure javascript solution. I should also add that the name and email address for each person will always be identical, so Michael will never have a different email address etc. Your help is much appreciated!

6
  • can we assume that the unique key is the contactdetails field only? or both the contactdetails AND name fields?
    – haxxxton
    Commented Feb 15, 2017 at 6:07
  • Don't add information as a comment, put it in the question. Also, add a Google apps script tag. Probably reduce will do the job, what have you tried?
    – RobG
    Commented Feb 15, 2017 at 6:07
  • @haxxxton yes the names and the contactdetails will always be identical for each person, the only thing would change for a person would be there task. Commented Feb 15, 2017 at 6:10
  • @RobG fair call, I added my comment to the main post, thanks. I didn't want to pigeon hole the question to Google apps scripts because it is a javascript problem which could help anyone. Commented Feb 15, 2017 at 6:11
  • 1
    may i suggest that you take your tasks for a single person as an array rather than separate json objects. I don't know if it is possible for you since it has something to do with google docs !
    – Sikorski
    Commented Feb 15, 2017 at 6:12

5 Answers 5

3

This would be a good opportunity to use the reduce function.

What we do is cycle through each of the original recipients list, see if we have already processed the element, if we have, append the task of the current element to the already processed element, otherwise, add the current recipient to the processed list

// original array
var recipients = [
    {name: 'Michael',task:'programming',contactdetails:'[email protected]'},
    {name: 'Michael',task:'designing',contactdetails:'[email protected]'},
    {name: 'Shane',task:'designing',contactdetails:'[email protected]'}
];
var recipientKeyList = []; // used to store the contacts we've already processed
// cycle through each recipient element
var newRecipients = recipients.reduce(function(allRecipients, recipient){
    // get the indexOf our processed array for the current recipient
    var index = recipientKeyList.indexOf(recipient.contactdetails);
    // if the contact details already exist, append the task
    if( index >= 0){
        allRecipients[index].task = allRecipients[index].task + ', ' + recipient.task;
        return allRecipients
    }else{ // otherwise append the recipient
        recipientKeyList.push(recipient.contactdetails)
        return allRecipients.concat(recipient);
    }

}, []);
3
  • There have been heaps of great answers and I will spend some time digesting the different options, however this code works great. Thanks so much for your help :) Commented Feb 15, 2017 at 6:32
  • 1
    Yep, that's pretty much exactly what I did, except I wrapped it in an IIFE to avoid unnecessary globals. ;-)
    – RobG
    Commented Feb 15, 2017 at 6:35
  • @RobG, one would hope that OP is including a snippet of their code that is already wrapped in an IIFE ;)
    – haxxxton
    Commented Feb 15, 2017 at 6:41
1
var recipients = [{name: 'Michael',task:'programming',contactdetails:'[email protected]'},{name: 'Michael',task:'designing',contactdetails:'[email protected]'},{name: 'Shane',task:'designing',contactdetails:'[email protected]'}];

var tempObj = {};
for (i=0; i<recipients.length; i++) {
    if (!tempObj[recipients[i]['name']]) {
        tempObj[recipients[i]['name']] = {};
        tempObj[recipients[i]['name']]['task'] = [];
    }
    tempObj[recipients[i]['name']]['task'].push(recipients[i]['task']);
    tempObj[recipients[i]['name']]['contactdetails'] = recipients[i]['contactdetails'];
}

var new_arr = [];
Object.keys(tempObj).forEach(function(key) {
    new_arr.push({name: key, task: tempObj[key]['task'].join(", "), contactdetails: tempObj[key]['contactdetails']})
});
4
  • can you also explain what are you doing in this code ?
    – Sikorski
    Commented Feb 15, 2017 at 6:14
  • Well I loop over array, unique them out by names and aggregate the task names. Commented Feb 15, 2017 at 6:18
  • Then again arrange them in array format by joining task names by ", ". Commented Feb 15, 2017 at 6:19
  • @kawadhiya21—the explanation should be in the answer, not as comments.
    – RobG
    Commented Feb 15, 2017 at 6:36
1

Iterate and look for same object if then append tasks like this

var recipients = [{
  name: 'Michael',
  task: 'programming',
  contactdetails: '[email protected]'
}, {
  name: 'Michael',
  task: 'designing',
  contactdetails: '[email protected]'
}, {
  name: 'Shane',
  task: 'designing',
  contactdetails: '[email protected]'
}];


var uniqueR = [];
var copyRecipients = JSON.parse(JSON.stringify(recipients));

copyRecipients .forEach(function(ele){
  var obj = uniqueR.find(function(e){
    return (e.name == ele.name && e.contactdetails == ele.contactdetails);
  });  
  if(obj){
    obj.task = obj.task + ", " + ele.task;
  }else{
    uniqueR.push(ele);  
  }
});

console.log(uniqueR)

1
  • That creates a link between the object in recipients and uniqueR that means you're modifying recipients too (i.e. uniqueR and recipients contain the exact same objects that are modified by the function, do console.log(recipients)). You probably need to copy the objects across, per other answers.
    – RobG
    Commented Feb 15, 2017 at 6:32
1

Convert array into an object with key as name (can be email also)

// original array
var recipients = [
    {name: 'Michael',task:'programming',contactdetails:'[email protected]'},
    {name: 'Michael',task:'designing',contactdetails:'[email protected]'},
    {name: 'Shane',task:'designing',contactdetails:'[email protected]'}
];

var recipientsObj = {};
for (var i = 0; i < recipients.length; i++) {
  var element = recipients[i];
  var recipientInObj = recipientsObj[element.name]
  if (recipientInObj) {
    // If a recipient is repeated with same task, here duplicates will appear
    recipientInObj.task += ', ' + element.task;
  } else {
    recipientsObj[element.name] = element;
  }
}
console.log(recipientsObj)

4
  • creating an array only to immediately join it seems like overkill no?
    – haxxxton
    Commented Feb 15, 2017 at 6:35
  • Added string concat alternative
    – Sangharsh
    Commented Feb 15, 2017 at 6:37
  • ... += ', ' + recipientsObj[element.name].task; is a lot less to type. ;-)
    – RobG
    Commented Feb 15, 2017 at 6:39
  • Improved based on comments.
    – Sangharsh
    Commented Feb 15, 2017 at 6:43
0

var newJSON = {}; $.each(recipients, function(i, json){ newJSON[json.contactdetails] = {name : json["name"], task : newJSON[json.contactdetails]!= undefined && newJSON[json.contactdetails]["task"]!= undefined ? newJSON[json.contactdetails]["task"] + ", " + json["task"] : json["task"] }

});

1
  • OP requires "a pure javascript solution"
    – haxxxton
    Commented Feb 15, 2017 at 6:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.