How to change multiple objects inside an array? - javascript

This is a two part question that I can't seem to solve. Part one requires that the entire object belonging to 'Theo' is removed somehow. Part two needs the object changed by editing one of the properties values belonging to 'Lorie'. Here's the array and instructions:
var employees = [{
"firstName": "Von",
"lastName": "Budibent",
"email": "vbudibent0#163.com",
"department": "Sales"
}, {
"firstName": "Catherina",
"lastName": "Swalowe",
"email": "cswalowe1#example.com",
"department": "Engineering"
}, {
"firstName": "Theo",
"lastName": "Trill",
"email": "ttrill2#sina.com.cn",
"department": "Services"
}, {
"firstName": "Elsy",
"lastName": "McCrorie",
"email": "emccrorie3#netscape.com",
"department": "Legal"
}, {
"firstName": "Lorie",
"lastName": "Handsheart",
"email": "lhandsheart4#fotki.com",
"department": "Research and Development"
}]
/* Create a function called 'employeeUpdater'. employeeUpdater will loop
over the array above and perform the following:
1. If employee's first name is Theo, remove that employee because he just
got fired.
2. If the employee's first name is Lorie, change her department to 'HR'.
3. Return the updated employee array. */
All I have to start is the following:
var employeeUpdater = () => {
for (let i = 0; i < employees.length; i++) {
if (employees[i] = 'Theo') {
employees.remove(employees[i]);
} else if (employees[i] = 'Lorie') {
employees.department = 'HR';
}
} return employees;
}
Something is wrong with the code

Javascript arrays don't have an method with name remove, instead you need to use Array#splice method for removing an item. But I can suggest this solution.
First use Array#filter to exclude the objects with name Theo then use Array#map or Array#forEach to iterate over the arrays an find the objects which name with Lorie and change it's department a.
var employees = [{
"firstName": "Von",
"lastName": "Budibent",
"email": "vbudibent0#163.com",
"department": "Sales"
}, {
"firstName": "Catherina",
"lastName": "Swalowe",
"email": "cswalowe1#example.com",
"department": "Engineering"
}, {
"firstName": "Theo",
"lastName": "Trill",
"email": "ttrill2#sina.com.cn",
"department": "Services"
}, {
"firstName": "Elsy",
"lastName": "McCrorie",
"email": "emccrorie3#netscape.com",
"department": "Legal"
}, {
"firstName": "Lorie",
"lastName": "Handsheart",
"email": "lhandsheart4#fotki.com",
"department": "Research and Development"
}];
var editedEmployees = employees
.filter(emp => emp.firstName !== 'Theo')
.map(emp =>
({
"firstName": emp.firstName,
"lastName": emp.lastName,
"email": emp.email,
"department": emp.firstName === 'Lorie' ? 'HR' : emp.department
}));
console.log(editedEmployees)

you can do it with splice():
var employeeUpdater = () => {
for (let i = 0; i < employees.length; i++) {
if (employees[i].firstName == 'Theo') {
employees.splice(i, 1);
i--;
} else if (employees[i].firstName == 'Lorie') {
employees[i].department = 'HR';
}
}
}return employees;

One of the tricky things about referencing objects in arrays is that you need to remember you have to reference them with the array index number and then the object name like employees[2].firstName would be how you reference Theo.
Also, the splice method is best for removing an array as stated above.
I believe the code you were trying to write would look like this:
var employeeUpdater = () => {
for (let i = 0; i < employees.length; i++) {
if (employees[i].firstName === 'Theo') {
employees.splice(i, 1);
} else if (employees[i].firstName === 'Lorie') {
employees[i].department = 'HR';
}
} return employees;
}

You should learn to program in an Object Oriented manner. Perhaps this will help:
//<![CDATA[
var pre = onload;
onload = function(){
if(pre)pre(); // change pre var name if using technique on other pages
var employees = [{
firstName:'Von',
lastName: 'Budibent',
email:'vbudibent0#163.com',
department:'Sales'
}, {
firstName:'Catherina',
lastName:'Swalowe',
email:'cswalowe1#example.com',
department:'Engineering'
}, {
firstName:'Theo',
lastName:'Trill',
email:'ttrill2#sina.com.cn',
department:'Services'
}, {
firstName:'Elsy',
lastName:'McCrorie',
email:'emccrorie3#netscape.com',
department:'Legal'
}, {
firstName:'Lorie',
lastName:'Handsheart',
email:'lhandsheart4#fotki.com',
department:'Research and Development'
}];
function EmployeeHandler(employeeArray){
this.employees = employeeArray;
this.removeByFirstName = function(firstName, caseSensitive){
var emp = this.employees;
var rx = caseSensitive ? new RegExp(firstName) : new RegExp(firstName, 'i');
for(var i=0,l=emp.length; i<l; i++){
if(emp[i].firstName.match(rx)){
this.employees.splice(i, 1);
return this;
}
}
return false;
}
this.removeByLastName = function(lastName, caseSensitive){
var emp = this.employees;
var rx = caseSensitive ? new RegExp(lastName) : new RegExp(lastName, 'i');
for(var i=0,l=emp.length; i<l; i++){
if(emp[i].lastName.match(rx)){
this.employees.splice(i, 1);
return this;
}
}
return false;
}
this.getByFirstName = function(firstName, caseSensitive){
var emp = this.employees;
var rx = caseSensitive ? new RegExp(firstName) : new RegExp(firstName, 'i');
for(var i=0,l=emp.length,em; i<l; i++){
em = emp[i];
if(em.firstName.match(rx)){
return em;
}
}
return false;
}
this.getByLastName = function(lastName, caseSensitive){
var emp = this.employees;
var rx = caseSensitive ? new RegExp(lastName) : new RegExp(lastName, 'i');
for(var i=0,l=emp.length,em; i<l; i++){
em = emp[i];
if(em.lastName.match(rx)){
return em;
}
}
return false;
}
}
var eh = new EmployeeHandler(employees);
var bb = eh.removeByFirstName('Theo').getByLastName('Budibent');
bb.department = 'Intelligent Design';
console.log(eh.employees); console.log(bb); console.log(eh.employees);
}
//]]>

Try this
var editedEmployees = employees
.filter(emp => emp.firstName !== 'Theo')
.map((emp) => {emp.department = emp.firstName === 'Lorie' ? 'HR' :
emp.department; return emp;});

If you like to work with lodash you can make your code easier to read.
So your script should become like this:
var _ = require('lodash');
/* Remove element */
_.remove(employees, function (employee) { return employee.firstName === 'Theo'; });
/* Get element to change */
var employee = _.find(employees,function (employee) { return employee.firstName === 'Lorie'; });
/* Change element */
employee.firstName = 'HR';
/* Right now employees store the right result */

Related

How to filter out objects if two keys are duplicate

const obj =
[
{
"id":"1",
"name":"a",
"email":"abc#gmail.com",
"expiryType":"premium"
},
{
"id":"2",
"name":"b",
"email":"abc#gmail.com",
"expiryType":"gold"
},
{
"id":"3",
"name":"b",
"email":"test#gmail.com",
"expiryType":"premium"
},
]
can somebody please help me how to filter out objects where email is same but i want to keep the one with expiry Type is premium ? How to achieve this using Javascript
Expected output would be
const obj =
[
{
"id":"1",
"name":"a",
"email":"abc#gmail.com",
"expiryType":"premium"
},
{
"id":"3",
"name":"b",
"email":"test#gmail.com",
"expiryType":"premium"
},
]
Assuming you want to keep the latest year's entry, you can keep a Map of the email addresses and years you've seen. See comments:
// The new list
const filtered = [];
// Known emails
const known = new Map();
// Loop through...
for (const entry of obj) {
// Get this email and expiry
const {email, expiryYear} = entry;
// Get the previous info if any
const previous = known.get(email);
if (previous) {
// If the previous one is older than this one,
// replace it with this one
if (previous.expiryYear < expiryYear) {
filtered[previous.index] = entry;
}
} else {
// Add this to the known list and the filtered array
known.set(email, {
index: filtered.length,
expiryYear
});
filtered.push(entry);
}
}
const obj = [
{
"id":"1",
"name":"a",
"email":"abc#gmail.com",
"expiryYear":"2020"
},
{
"id":"2",
"name":"a",
"email":"abc#gmail.com",
"expiryYear":"2019"
},
{
"id":"3",
"name":"b",
"email":"test#gmail.com",
"expiryYear":"2020"
},
];
// The new list
const filtered = [];
// Known emails
const known = new Map();
// Loop through...
for (const entry of obj) {
// Get this email and expiry
const {email, expiryYear} = entry;
// Get the previous info if any
const previous = known.get(email);
if (previous) {
// If the previous one is older than this one,
// replace it with this one
if (previous.expiryYear < expiryYear) {
filtered[previous.index] = entry;
}
} else {
// Add this to the known list and the filtered array
known.set(email, {
index: filtered.length,
expiryYear
});
filtered.push(entry);
}
}
console.log(filtered);
This has the advantage of not constantly re-scanning the new list for known entries.
You can filter out whole object based on unique key you want as below.
const obj =
[
{
"id": "1",
"name": "a",
"email": "abc#gmail.com",
"expiryType": "premium"
},
{
"id": "2",
"name": "b",
"email": "abc#gmail.com",
"expiryType": "gold"
},
{
"id": "3",
"name": "b",
"email": "test#gmail.com",
"expiryType": "premium"
}
]
function arrayUnique(arr, uniqueKey) {
const flagList = []
return arr.filter(function(item) {
if (flagList.findIndex(flagItem => flagItem[uniqueKey] === item[uniqueKey]) === -1) {
flagList.push(item)
return true
}
})
}
Method Calling....
let newObj = arrayUnique(obj,'email')
Output:
newObj = [
{
"id": "1",
"name": "a",
"email": "abc#gmail.com",
"expiryType": "premium"
},
{
"id": "3",
"name": "b",
"email": "test#gmail.com",
"expiryType": "premium"
}
]
Hope this helps.
You can do it simply with 2 loops. Maybe not the fastes but the simplest:
function deleteDouble(array, objectKey) {
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < array.length; j++) {
if (i == j) {
continue;
}
if (array[i][objectKey] == array[j][objectKey]) {
array.splice(i, 1);
i = 0;
j = 0;
break;
}
}
}
return array;
}
deleteDouble(obj, "email");

Display the difference between two JS objects

I'm trying to display the name of property where their values are difference.
Then, I'm trying to display the property which is not present on the other variable
myObj1 = {
"name": "John",
"age": "45",
"car": 20,
"test": 30,
"example": 20
};
myObj2 = {
"name": "John",
"age": "30",
"car": 10,
"example": 10
};
// or
//myObj1 = { "name":"John", "age":"45", "car":20 };
//myObj2 = { "name":"John", "age":"30", "car":10,"test":30 };
// find keys
keyObj1 = Object.keys(myObj1);
keyObj2 = Object.keys(myObj2);
// find values
valueObj1 = Object.values(myObj1);
valueObj2 = Object.values(myObj2);
// find max length to iterate
if (keyObj1.length > keyObj2.length) {
var biggestKey = keyObj1.length;
} else {
var biggestKey = keyObj2.length;
}
// now compare their keys and values
for (var i = 0; i < biggestKey; i++) {
//console.log(biggestKey)
if (keyObj1[i] == keyObj2[i] && valueObj1[i] !== valueObj2[i]) {
console.log('property:' + keyObj1[i]);
console.log('first:' + valueObj1[i]);
console.log('second:' + valueObj2[i]);
}
}
Actual result:
property: age, 45,30
property: car,20,10
property: test,30,10
property: example,20,undefined
Expected result:
property: age, 45,30
property: car,20,10
property: test,30,undefined
property: example,20,10
Problems
biggestKey is a length instead of array
compare object by key in biggestKey
myObj1 = {
"name": "John",
"age": "45",
"car": 20,
"test": 30,
"example": 20
};
myObj2 = {
"name": "John",
"age": "30",
"car": 10,
"example": 10
};
// find keys
keyObj1 = Object.keys(myObj1);
keyObj2 = Object.keys(myObj2);
// find max length to iterate
if (keyObj1.length > keyObj2.length) {
var biggestKey = keyObj1;
} else {
var biggestKey = keyObj2;
}
// now compare their keys and values
for (var i = 0; i < biggestKey.length; i++) {
//console.log(biggestKey)
var key = biggestKey[i];
if (myObj1[key] != myObj2[key]) {
console.log('project:', key, myObj1[key], myObj2[key]);
}
}
Hope it will help you
function getDifference(compareObject, baseObject) {
function difference(compareObject, baseObject) {
return _.transform(compareObject, function(results, value, key) {
if (!_.isEqual(value, baseObject[key])) {
results[key] = (_.isObject(value) && _.isObject(baseObject[key])) ? changes(value, baseObject[key]) : value;
}
});
}
return difference(compareObject, baseObject);
}
The trick is to iterate through both objects and to ignore the properties that exist in both objects in the second loop.
var myObj1 = {
"name": "John",
"age": "45",
"car": 20,
"test": 30,
"example": 20
};
var myObj2 = {
"name": "John",
"age": "30",
"car": 10,
"example": 10
};
for (var key in myObj1) {
if (myObj1[key] !== myObj2[key]) console.log("property:", key, myObj1[key], myObj2[key]);
}
for (key in myObj2) {
if (!(key in myObj2)) { // ignore if key exists in myObj1 (if it exists, then it got checked in the previous loop)
if (myObj1[key] !== myObj2[key]) console.log("property:", key, myObj1[key], myObj2[key]);
}
}

Compare two object arrays and combine missing objects

I have 2 object arrays. The 1st is an array of managers. The 2nd is an array of selected managers from the 1st array. The difference is I added a property selected: true. I need to now replace the the managers in the first array with selected managers. I am doing this with an AngularJS service I created. I'm sure there is much simpler solution so I'm open to suggestions. JavaScript, jQuery, lodash, LINQ.js are good.
I have a plunker and I have displayed the result I need. Notice the manager that does not have the selected:true property.
plunker
var app = angular.module("mainModule", []);
var MainController = function($scope, service) {
var eventUsers = [
{
"event_Users_ID":1009,"event_ID":11,"user_ID":"15e640c1-a481-4997-96a7-be2d7b3fcabb"
},{
"event_Users_ID":1010,"event_ID":11,"user_ID":"250a19be-e661-4c04-9a50-c84b0e7349b7"
},{
"event_Users_ID":1011,"event_ID":11,"user_ID":"4cada7f0-b961-422d-8cfe-4e96c1fc11dd"
},{
"event_Users_ID":1013,"event_ID":11,"user_ID":"a3125317-5deb-426d-bbb1-06d3bd4ebaa6"
}];
var managers = [
{
"id": "15e640c1-a481-4997-96a7-be2d7b3fcabb",
"fullName": "Kul Srivastva"
},{
"id": "250a19be-e661-4c04-9a50-c84b0e7349b7",
"fullName": "Todd Brothers"
}, {
"id": "4cada7f0-b961-422d-8cfe-4e96c1fc11dd",
"fullName": "Rudy Sanchez"
}, {
"id": "79823c6d-de52-4464-aa7e-a15949fb25fb",
"fullName": "Mike Piehota",
}, {
"id": "a3125317-5deb-426d-bbb1-06d3bd4ebaa6",
"fullName": "Nick Broadhurst"
}];
$scope.result = service.eventUserMatch(eventUsers, managers);
};
function service() {
var vm = this;
vm.eventUserMatch = function (eventUsers, managers) {
var arry = [];
arry = $.map(eventUsers, function (eventUser) {
var manager = $.grep(managers, function (user) {
return user.id === eventUser.user_ID;
})[0];
eventUser.id = manager.id;
eventUser.fullName = manager.fullName;
eventUser.selected = true;
return eventUser;
});
return arry;
};
}
app.controller("MainController", MainController);
app.service('service', service);
You can use Array#map.
// Get all the event user IDs in an array
var eventUserIds = eventUsers.map(e => e.user_ID);
// Iterate over managers
managers = managers.map(e => {
// If manager is present in the event users, `select` it
if (eventUserIds.indexOf(e.id) !== -1) {
e.selected = true;
}
return e;
});
var eventUsers = [{
"event_Users_ID": 1009,
"event_ID": 11,
"user_ID": "15e640c1-a481-4997-96a7-be2d7b3fcabb"
}, {
"event_Users_ID": 1010,
"event_ID": 11,
"user_ID": "250a19be-e661-4c04-9a50-c84b0e7349b7"
}, {
"event_Users_ID": 1011,
"event_ID": 11,
"user_ID": "4cada7f0-b961-422d-8cfe-4e96c1fc11dd"
}, {
"event_Users_ID": 1013,
"event_ID": 11,
"user_ID": "a3125317-5deb-426d-bbb1-06d3bd4ebaa6"
}];
var managers = [{
"id": "15e640c1-a481-4997-96a7-be2d7b3fcabb",
"fullName": "Kul Srivastva"
}, {
"id": "250a19be-e661-4c04-9a50-c84b0e7349b7",
"fullName": "Todd Brothers"
}, {
"id": "4cada7f0-b961-422d-8cfe-4e96c1fc11dd",
"fullName": "Rudy Sanchez"
}, {
"id": "79823c6d-de52-4464-aa7e-a15949fb25fb",
"fullName": "Mike Piehota",
}, {
"id": "a3125317-5deb-426d-bbb1-06d3bd4ebaa6",
"fullName": "Nick Broadhurst"
}];
var eventUserIds = eventUsers.map(e => e.user_ID);
managers = managers.map(e => {
if (eventUserIds.indexOf(e.id) !== -1) {
e.selected = true;
}
return e;
})
console.log(managers);
document.getElementById('result').innerHTML = JSON.stringify(managers, 0, 4);
<pre id="result"></pre>
would this work? Loop through the new array of managers, find the index using lodash of a matching manager object in the old manager array and replace it in the old manager array with the manager from the new manager array if found?
There's probably a more efficient way to write a solution to this but assuming I'm understanding your problem correctly I believe this should work? Can't test as I'm at work currently.
for(var i=0; i < SelectedManagersArray.length; i++){
var index = _.findIndex(OldManagersArray, {id: SelectedManagersArray[i].id, fullName: selectedManagersArray[i].fullName);
//I believe lodash returns a -1 if a matching index isn't found.
if(index !== -1){SelectedManagersArray[index] = OldManagersArray[i]}
}
Simple implementation:
for(var i = 0; i < eventUsers.length; i++) {
for(var j = 0; j < managers.length; j++) {
if(eventUsers[i].user_ID === managers[j].id) {
managers[j].selected = true;
}
}
}
As you said, I do think there may be an easier way to do this.
I advise you to pick a look to SugarJs which is a JavaScript library that extends native objects with so helpful methods.
In your case the doc on Arrays.
For me, it helps a lot dealing with a lot of native JavaScript Object (JSON).

Take Distinct values to populate Drop down

{ "Result": { "tags": [ { "name": "ABC", "email": "abc1#example.com", "sms": 123 }, {
"name": "ABC", "email": "abc2#example.com", "sms": 456 }, { "name": "ABC", "email":
"abc3#example.com", "sms": 789 }, { "name": "XYZ", "email": "xyz1#example.com", "sms": 976
}, { "name": "ABC", "email": "xyz2#example.com", "sms": 543 } ] } }
I have a JSON data like this. I want to Parse this JSON in PHP or Javascript to populate them in three drop downs.
Name | Email | SMS
But I need to Populate the distinct names in the dropdowns and populate email and sms based on selecting the name.
So far I just created the dropdowns.
Fiddle Link : http://jsfiddle.net/CAB2z/
Example:
Name should have : ABC | XYZ only once (Distinct : Should not repeat the same value).
When we select ABC, the three emails and phone numbers for "ABC" from the JSON should be populated in the second and third dropdown.
Try this,
$(function(){
var json = {
"Result": {
"tags": [{"name": "ABC","email": "abc1#example.com","sms": 123},
{"name": "ABC","email": "abc2#example.com","sms": 456},
{"name": "ABC","email":"abc3#example.com","sms": 789},
{"name": "XYZ","email": "xyz1#example.com","sms": 976},
{"name": "XYZ","email": "xyz2#example.com","sms": 543}]
}
};
var name = [],obj = {};
$(json.Result.tags).each(function (k, v) {
name[k] = (v.name);
obj[k] = {name: v.name,email: v.email,sms: v.sms};
});
$($.unique(name)).each(function (i, v) {
$('#name').append('<option value="'+v+'">'+v+'</option>');
});
$('#name').on('change', function () {
var $that = $(this);
$('#email').html('');$('#sms').html('');
$.each(obj,function (i, v) {
if( $that.val() == v.name) {
$('#email').append('<option value="'+v.email+'">'+v.email+'</option>');
$('#sms').append('<option value="'+v.sms+'">'+v.sms+'</option>');
}
});
}).change();
});
Live Demo
It will returns all results you want. Just append the vaues in
dropdown its your part.
var resultArray = r.Result.tags;
var unique = {};
var distinctName = [];
var email = [];
var sms = [];
for( var i in resultArray ){
if( typeof(unique[resultArray[i].name]) == "undefined"){
distinctName.push(resultArray[i].name); // push the unique names into the array
}
unique[resultArray[i].name] = 0;
email.push(resultArray[i].email); // push the email into the array
sms.push(resultArray[i].sms) // push the sms into the array
}
console.log(distinctName);
console.log(email);
console.log(sms);
In JavaScript, with jQuery, you can do:
var names, emails, smses;
(function() {
data = JSON.parse(data); // Get the data formatted.
var result = {
name: {},
email: {},
sms: {}
};
$.each(data.Result.tags, function(index, value) {
result.name [value.name] = true; // True won't be used, it can be any value.
result.email[value.email] = true;
result.sms [value.sms] = true
});
names = Object.keys(result.name);
emails = Object.keys(result.email);
smses = Object.keys(result.sms);
} ()); // Temporary variables (like result) are destroyed.
// names, emails and smses contain your data.

How apply ko.utils.arrayGetDistinctValues on two dimensional arrays

I have an ko.observableArray with two dimensions, i.e. "id" and "name".
Id will always be distinct, but name can hold the same value.
self.myArray = ko.observableArray( [
{ "id": "1", "name": "Barbara" }, 
{ "id": "2", "name": "Edwin" }, 
{ "id": "3", "name": "Barbara" } 
] );
However I want to filter the array so that my result holds only the first occurrence of "name".
The result I want is:
self. myFilteredArray = [
{ "id": "1", "name": "Barbara" }, 
{ "id": "2", "name": "Edwin" } 
];
I have been trying to figure this out using ko.utils.arrayGetDistinctValues(), but how can I utilize it on solely one chosen dimension?
You could use a computed for this:
viewModel.myFilteredArray = ko.computed(function() {
var rv = [], names = [];
for(var i=0; i<this.myArray().length; i++) {
if(names.indexOf(this.myArray()[i].name) === -1) {
rv.push(this.myArray()[i]);
names.push(this.myArray()[i].name);
}
}
return rv;
}, viewModel);
I can suggest a function, that loops through the array, builds map of property values for each item and checks, whether the current value was already added. Something like this:
function filterByFirstOccurance(arr, prop) {
var propValuesHash = {},
result = [];
for (var i = 0, l = arr.length; i < l; i++) {
var item = arr[i],
propValue = item[prop];
if (item.hasOwnProperty(prop) && !propValuesHash[propValue]) {
propValuesHash[propValue] = true;
result.push(item);
}
}
return result;
};
Fiddle

Categories

Resources