I have a javascript array like so:
var recipients = [{
name: 'Michael',
task: 'programming',
contactdetails: 'michael#michael.com'
}, {
name: 'Michael',
task: 'designing',
contactdetails: 'michael#michael.com'
}, {
name: 'Shane',
task: 'designing',
contactdetails: 'shane#shane.com'
}];
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: 'michael#michael.com'
}, {
name: 'Shane',
task: 'designing',
contactdetails: 'shane#shane.com'
}];
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!
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:'michael#michael.com'},
{name: 'Michael',task:'designing',contactdetails:'michael#michael.com'},
{name: 'Shane',task:'designing',contactdetails:'shane#shane.com'}
];
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);
}
}, []);
var recipients = [{name: 'Michael',task:'programming',contactdetails:'michael#michael.com'},{name: 'Michael',task:'designing',contactdetails:'michael#michael.com'},{name: 'Shane',task:'designing',contactdetails:'shane#shane.com'}];
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']})
});
Iterate and look for same object if then append tasks like this
var recipients = [{
name: 'Michael',
task: 'programming',
contactdetails: 'michael#michael.com'
}, {
name: 'Michael',
task: 'designing',
contactdetails: 'michael#michael.com'
}, {
name: 'Shane',
task: 'designing',
contactdetails: 'shane#shane.com'
}];
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)
Convert array into an object with key as name (can be email also)
// original array
var recipients = [
{name: 'Michael',task:'programming',contactdetails:'michael#michael.com'},
{name: 'Michael',task:'designing',contactdetails:'michael#michael.com'},
{name: 'Shane',task:'designing',contactdetails:'shane#shane.com'}
];
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)
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"] }
});
Related
For my scenario, I need to push elements to an addresses array which contains objects. I'm working with vue.js.
My current working function is:
propagateCustomerInfo(selectedOption, id){
// Propagate addresses
this.addresses = selectedOption.addresses
// Propagate contact's addresses
for (var i = selectedOption.contacts.length - 1; i >= 0; i--) {
for (var j = selectedOption.contacts[i].addresses.length - 1; j >= 0; j--) {
let address = selectedOption.contacts[i].addresses[j]
address.contact = selectedOption.contacts[i]
this.addresses.push(address)
}
}
},
the selectedOption object has the below structure:
{
addresses: [
{
id: 0,
street: 'My street'
},
{...}
],
contacts: [
{
id: 0,
name: 'Lorem Ipsum',
addresses: [
{
id: 0,
street: 'My street'
},
{...}
],
}
]
}
Besides pushing every contact's address object to this.addresses array I need to append the contact to the address itself for multiselect rendering purposes. That's why I'm doing address.contact = selectedOption.contacts[i]
I almost sure that this can be accomplished in a prettiest way with some mapping/reduce combination but I can't figure out how to do it.
Any help will be really appreciated.
Thanks!
if you want to combine all address in contact variable to addresses variable:
this.contacts.map(contact => this.addresses.push(...contact.addresses))
Edit.
to inject the contact.id and contact.name:
this.contacts.map(contact => {
let temp = []
contact.addresses.map(address => {
temp.push({
name: contact.name,
id: contact.id,
...address
})
})
this.addresses.push(...temp)
})
I have this Javascript Object as below format but I want to convert it to another format as below:
I've pass value form let data = $('#clientForm').serializeArray();
Original format
let data = $('#clientForm').serializeArray();
{ name="addr_types", value="RESID"}
Wanted Format
{addr_types:"RESID"}
Or another format
{"addr_types":"RESID"}
Assuming a valid object, you could just assign the wanted property with the given key/value pair.
var source = { name: "addr_types", value: "RESID" },
target = {};
target[source.name] = source.value;
console.log(target);
ES6 with computed property
var source = { name: "addr_types", value: "RESID" },
target = { [source.name]: source.value };
console.log(target);
Given that your original object is a correct one
var original = {
name: "addr_types",
value: "RESID"
};
console.log(original);
var newName = original.name;
var newValue = original.value;
var newObject = {};
newObject[newName] = newValue;
console.log(newObject);
You can simply do it using .map() function. bellow is the example.
var original = [{
name: "addr_types",
value: "Work"
},{
name: "village",
value: "Vang Tobang"
},{
name: "commune",
value: "Tang Krasang"
},{
name: "destric",
value: ""
},{
name: "city",
value: "Com Pong Thom"
},{
name: "country",
value: "combodia"
},
];
newArray = original.map(function(item){
return {[item.name]: item.value}
});
If your data container is not array then you can simply create as like bellow.
newArray = [original].map(function(item){
return {[item.name]: item.value}
});
Here is the jsfiddle link: https://jsfiddle.net/kzrngch6/
I need some help in manipulating a value pair array to return a string in a specific layout
This is the string i am trying to achieve:
'&test=id:1111|na:shoes|ca:shoe&test=id:2222|na:top|ca:tops'
This is the array I am trying to manipulate into my string
var prodlist =
[
{
name: 'shoe',
sku: '1111',
category: 'shoes'
},
{
name: 'top',
sku: '2222',
category: 'tops'
}
]
Here is what I have tried.
I added the 'deleteme' into the array thinking i could to a substitute later down the script.
function(){
var prods = prodlist;
var array = [];
for (var i = 0; i < prods.length; i++) {
var sku = (prods[i]['sku']);
var name = (prods[i]['name']);
var cat = (prods[i]['category']);
array.push({
deleteme: &test=id,
id: sku,
na: name,
ca: cat,
});
}
var newarray = array.toString();
return newarray;
}
At the moment this function returns '[object Object],[object Object]'
any help would be much appreciated.
Thanks
Quick and easy
function prods() {
var prods = prodlist;
var array = [];
for (let product of prods)
array.push('test=id:' + product.sku+ '|na:' + product.name + '|ca:' + product.category);
return '&' + array.join('&');
}
how about something like this?
var prodlist =
[{name: 'shoe',
sku: '1111',
category: 'shoes'},
{name: 'top',
sku: '2222',
category: 'tops'}]
var strTemplate = "&test=id:%sku%|na:%name%|ca:%category%"
prodlist.map( function(obj){
return strTemplate.replace(/%(\w+)%/g, function($1, $2) {
return obj[$2]
})
}).join('')
//returns
// "&test=id:1111|na:shoe|ca:shoes&test=id:2222|na:top|ca:tops"
or ES6 version (edited it down further as suggested by nnnnnn )
prodlist.map( obj => strTemplate.replace(/%(\w+)%/g, ($1, $2) => obj[$2])).join('')
I have 2 arrays of objects exclude and people, I want to create a new object by checking exclude properties against people properties and only adding objects in people that don't feature in exclude. So far my attempt is a little wild and wondering if someone can help make things a little better or offer a nicer solution?
Fiddle http://jsfiddle.net/kyllle/k02jw2j0/
JS
var exclude = [{
id: 1,
name: 'John'
}];
var peopleArr = [{
id: 1,
name: 'John'
}, {
id: 2,
name: 'James'
}, {
id: 3,
name: 'Simon'
}];
var myObj = [];
for (key in peopleArr) {
for (k in exclude) {
if (JSON.stringify(peopleArr[key]) != JSON.stringify(exclude[k])) {
console.log(peopleArr[key]);
myObj.push(peopleArr[key]);
}
}
}
console.log(myObj);
Under the assumption that exclude can have multiple items, I would use a combination of filter() and forEach() :
var newArray = peopleArr.filter(function(person) {
include = true;
exclude.forEach(function(exl) {
if (JSON.stringify(exl) == JSON.stringify(person)) {
include = false;
return;
}
})
if (include) return person;
})
forked fiddle -> http://jsfiddle.net/6c24rte8/
You repeat some JSON.stringify calls.
You can convert your arrays to JSON once, and then reuse it. Also, you can replace your push by Array.prototype.filter.
var excludeJson = exclude.map(JSON.stringify);
peopleArr = peopleArr.filter(function(x) {
return excludeJson.indexOf(JSON.stringify(x)) === -1;
});
Here is the working snippet:
var exclude = [{
id: 1,
name: 'John'
}];
var peopleArr = [{
id: 1,
name: 'John'
}, {
id: 2,
name: 'James'
}, {
id: 3,
name: 'Simon'
}];
var excludeJson = exclude.map(JSON.stringify);
peopleArr = peopleArr.filter(function(x) {
return excludeJson.indexOf(JSON.stringify(x)) === -1;
});
document.body.innerText = JSON.stringify(peopleArr);
This can be achieved with .filter and .findIndex
var myObj = peopleArr.filter(function(person){
var idx = exclude.findIndex(function(exc) { return person.id == exc.id && person.name == exc.name; });
return idx == -1; // means current person not found in the exclude list
});
I have explicitly compared the actual properties back to the original, there is nothing particularly wrong with your original way of comparing the stringified version (JSON.stringify(e) == JSON.stringify(x) could be used in my example)
I'm trying to remove objects from an array of object using a delta data i'm getting from server. I'm using underscore in my project.
Is there a straight forward way to do this, rather going with looping and assigning ?
Main Array
var input = [
{name: "AAA", id: 845,status:1},
{name: "BBB", id: 839,status:1},
{name: "CCC", id: 854,status:1}
];
Tobe Removed
var deltadata = [
{name: "AAA", id: 845,status:0},
{name: "BBB", id: 839,status:0}
];
Expected output
var finaldata = [
{name: "CCC", id: 854,status:1}
]
Try this
var finaldata = _.filter(input, function(item) {
return !(_.findWhere(deltadata, {id: item.id}));
});
It does assume that you have unique ID's. Maybe you can come up with something better.
Here's a simple solution. As others have mentioned, I don't think this is possible without a loop. You could also add checks for status and name in the condition, as this just compares IDs.
var finaldata = input.filter(function(o) {
for (var i = 0; i < deltadata.length; i++)
if (deltadata[i].id === o.id) return false;
return true;
});
A simple filter will do it:
var finaldata = _.filter(input, function(o) {
return _.findWhere(deltadata, o) === undefined;
});
A little more efficient than the findWhere would be creating a lookup map with ids to remove, and then filtering by that:
var idsToRemove = _.reduce(deltadata, function(m, o) {
m[o.id] = true;
return m;
}, {});
var finaldata = _.reject(input, function(o) { return o.id in idsToRemove; });