How to pass by reference (simulation) - javascript

I'm having a trouble approaching to this problem, althouh I have a working solution I doubt it is the most optimal one.
Here is the problem:
Imagine an array of objects, each object represents a person.
var people = [
{id:1, name:"John", points: 50},
{id:2, name:"Mark", points: 80},
{id:3, name:"Peter", points: 25},
];
In our people array, we have 3 persons with an unique id property.
Now imagine that we have multiple functions that modify/update person objects.
Obviously this wouldn't work, since the outer object won't be affected
by the changes made in incrementPoints() function.
var myPerson = people[0];
incrementPoints(myPerson){
myPerson.points++;
};
// myPerson.points = 50
addPoints(myPerson); // We're passing an person object to addPoints;
// myPerson.points = 50 (Did not change, not affected by addPoints)
This however, would work! But the price we pay is the cost of
iteration through persons array and matching the id of desired person.
function getPersonIndexById(personId){
// Iterate through all persons in 'people' array
for(var index = 0; index < people.length; index++)
people[i].id === personId ? return index : continue;
}
function incrementPoints(personId){
people[ getPersonIndexById(personId) ].points++;
}
function decrementPoints(personId){
people[ getPersonIndexById(personId) ].points--;
}
Is there a better/simpler/cleaner/intended concept for dealing with such situations. Obviously, the ideal solution would be a pass by &reference but javascript does not allow that. I'm not trying to do achieve an useless hack, but rather get understanding of what developers do when they stumble upon similar situations and how they solve them.

var people = [
{id:1, name:"John", points: 50},
{id:2, name:"Mark", points: 80},
{id:3, name:"Peter", points: 25},
];
var myPerson = people[0];
function incrementPoints(myPerson){
myPerson.points++;
};
function addPropertyToPerson(myPerson, lastname) {
myPerson.lastName = lastname;
}
// The properties of the myPerson object can still be modified since
// the value passed in to the function is the reference to the object
incrementPoints(myPerson);
console.log(myPerson);
// Similarly, additional properties can still be added since
// the value passed in to the function is the reference to
// the outer object
addPropertyToPerson(myPerson, "smith");
console.log(myPerson);

Objects are passed as reference
You defined a function with name incrementPoints with a wrong syntax but you are calling addPoints. I hope it is a typo/mistake.
if I suppose it is addPoints then it is working fine. You will get 51 points after that function call.
You can use Array.prototype.find to find a person by id, it is builtin and it will be fast.
function incrementPoints(personId){
var person = people.find(function(p){
return p.id === personId;
});
if (person) {
person.points++;
}
}

I would prefer to convert array to map while getting data.
var personMap = {}; people.forEach(function(person){
personMap[id] = person;
});
With this now you have map
You can get person as personMap[personId]
Here creating map is one time activity so you need a single round of iteration
Please bear with my response.. I am replying from mobile so formatting might be not good

Related

How can I add the data of one JS object to another

In the function there is an empty JS object
var globalDataObject = [{}];
Then, there is a loop that goes over an array of users, stores the properties of each user in variables (ex. name, lastName, ...) and creates an object for each user:
//create an object containing the current name
const currentObject = {
'profile': {
'name': nameVariable,
'lastName': lastNameVariable
}
};
What is the right way to add the data of currentObject to the globalDataObject once it's created? So that at the end the globalDataObject should be:
var globalDataObject = [
'profile': {
'name': 'John',
'lastName': 'Smith'
},
'profile': {
'name': 'Ann',
'lastName': 'Lee'
},
'profile': {
'name': 'Dan',
'lastName': 'Brown'
}
];
Important thing is that globalDataObject must be the JS object of the specified format (not the object containing multiple objects and not the array) since once it's created it is going to be converted into XML.
You can create your global object like an array:
globalDataObject = [];
And then just push in it:
globalDataObject.push(currentObject);
I dont understand the end goal of the question and why you dont just use .push() as suggested before. You havent accepted that answer so i assume its not the end goal.
globalDataObject must be the JS object of the specified format (not
the object containing multiple object and not the array)
1) The format you gave is not valid JavaScript.
2) Why cant you have an array of objects or object with nexted objects and covert that into xml
3) Why do you want to convert json into xml in the first place.
I'll take a wild guess and assume you mis-typed the globalDataObject as array, and meant it to be an object with multiple 'profile' keys. Neither is valid javascript.
Since you can't have multiple keys with same name and expect them to have different values, I propose you to use unique "indexes" for each profile.( like an array...but an object).
// init the object
const userProfiles = {};
// then later add to it like this.
let profile1 = {name: "john", lastname: "smith"};
let profile2 = {name: "alice", lastname: "wonderland"};
userProfiles[1] = profile1;
userProfiles[2] = profile2;
// you can then torn it into an array of user profile objects like this
Object.keys(userProfiles).map((index) => {return userProfiles[index];})

concatenate fields in JS multidim Array, sort, then create different type of JS object array

I want to take an array that looks like the following:
var contacts = [
{account: 'Acme', firstName: 'John', lastName: 'Snow'},
{account: 'Metal Industries', firstName: 'Ted', lastName: 'Smith'}
];
Note: contacts can have the same account name.
and create a function to convert the data to something that instead is an object with the following structure that's like a map where the key is account name and value is an array of alphabetized full names as below:
var acctContactObject = {
'Acme': ['John Snow','Kyle Johnson','Sara Butler'],
'HiTech Corp': ['Arnold Williams','Jason Fernandez','Sam Johnson']
};
I'm not certain that I'm taking the correct approach and wanted to seek some sage advice before proceeding. Here's what I've written so far and "psuedocode" for where I'm heading.
function convertAccountArrayToObject(contacts){
this.account = contacts.account;
this.firstName = contacts.firstName;
this.lastName = contacts.lastName;
this.sort(function(a, b) {
return a.account.localeCompare(b.account);
});
var aco = new acctContactObject();
var name;
var nameArray = [];
for(var member of this){
//this is where I get stuck
//I could create a new array to hold the account with full name
//but somehow need to add them to an array that I can sort on
//
//assuming I used an intermediate array...
//create new acctContactObject
//For acct in intermediate array
//add name to another single array and sort alphabetically
//put acct name and sorted list of names into new object
//after end of loop, return object
I've been searching to see if there's a way to do a secondary sort on a multidimensional array, but didn't find what I was looking for. I've also run across mention of "merging" properties, but am not certain if that would allow me to concatenate the values for the first and last names properly.
I don't do a lot of JS, at least not of this kind, so would appreciate knowing if I'm on the right track. Any suggestions or guidance towards a cleaner way to approach this would be appreciated.
The simplest way to do it will be as follows.
Note:I have modified contacts to include the case of same account names.
var contacts = [
{account: 'Acme', firstName: 'John', lastName: 'Snow'},
{account: 'Metal Industries', firstName: 'Ted', lastName: 'Smith'},
{account: 'Metal Industries', firstName: 'Bolt', lastName: 'Coder'}
];
function convertAccountArrayToObject(contacts){
var returnObj={},key;
contacts.forEach(function(v,i){
key=v.account;
if(!returnObj[key]){
returnObj[key]=[];
}
returnObj[key].push(v.firstName+" "+v.lastName);
});
return returnObj;
}
acctContactObject=convertAccountArrayToObject(contacts);
Upvote if you find this helpful.

Check if an object has a key in javascript

I have two arrays of objects, and I want to filter the first one according to whats on the second one. Here's an example:
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
So in this case what I want to return is an array with the objects that have id's 23 and 54 of the first array, with all its possible properties (in this case, title).
Could you give me any hint that could help me?
Get a list of the indexes you want to search on using map:
var indexes = ary2.map(function (el) {
return el.id;
});
filter the results based on the list of indexes:
var result = ary1.filter(function (el) {
return indexes.indexOf(el.id) > -1;
});
DEMO
This might help you.
Loop through ary2, building up an array of each id value (let's call this array existingIds).
After that loop, now loop through ary1. For each item in ary1, check to see if the id value exists in the existingIds array that we just built up. If it does, append the current item to a result array.
I could write the code for you, but it will be a better learning experience if you first try this yourself :)
Might as well make use of some functional programming built into javascript.
filteredResults = ary1.filter(function(ele){
return (ary2.map(function(idobj){return idobj.id;}).indexOf(ele.id)>-1)
})
filter(function) will iterate through each element of an array, passing it through a callback function. From within that callback iff a true is returned, that value is kept. If false, that value is filtered out.
Also map(function) will iterate through each element of an array passing a callback value as well. All values returned from map callback will be injected into the result. So we can take the id from each element in ary2 and return it in the map function.
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
//Filter for the available ID's, store the resulting objects in a new array
filteredResults = ary1.filter(function(ele){
//map creates an array of just ID's
return (ary2.map(function(idobj){return idobj.id;}).indexOf(ele.id)>-1)
})
//now do whatever you were planning on doing with your results/
var res = document.getElementById("results");
filteredResults.forEach(function(ele){
res.innerHTML+="<li>{id:"+ele.id + ",title:" +ele.title+"}</li>"
})
console.log(filteredResults);
<ul id="results"></ul>
try this:
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
var newary=[];
for(x in ary1){
for(y in ary2){
if(ary1[x].id == ary2[y].id){
newary.push(ary1[x]);
}
}
}
console.log(newary);// here newary will be your return newary;

Underscore.js - without and difference methods trouble

I am trying to use the _.without and _.difference methods in the underscore.js library with no luck.
Here is some code.
var someIds = _.pluck(parsedID1, 'id');
var otherIds = _.pluck(parsedID2, 'id);
Here is where the trouble starts, I want to remove all of the otherIds out of the someId's list. So I have two options according to the website, either I can use _.difference || _.without. I use them like so...
var newArray = _.without(_.toArray(someIds), _.toArray(otherIds));
I have also tried to do this with _.difference as well, but I cant seem to get the methods to do anything other than return a copy of the first argument into the function. I have also tried passing the arguments into the functions without using the _.toArray() but the same thing happens.Has anyone ever encountered this error before?
EDIT:
I have tried the way as proposed below. I will give some more code in hopes of fixing this.
The arrays that I am passing in as arguments are in the following format.
var array = ['100004191488120', '100004191488321'];
When I pass into the _.difference I do as follows:
var newArray = _.difference(someIds, otherIds);
If someIds length is 657 and otherIds is 57 I should be getting a result of 600 Id's. Instead I get a result of whatever the length of the first argument is, being 657.
EDIT 2: Solved
I figured out what the problem was, after all that frustration the problem lied with the second argument to difference I was passing in.
I was doing a db query and getting back a list that looked like the following.
[{ _id: 514721152222111116666777, facebook: { id: '123456789' } },
{ _id: 514721152222111116666778, facebook: { id: '12345678' } },]
After I received those results I wanted to get the facebook id so I did the following,
var array = _.pluck(users, 'facebook.id');
Thats were the problem was, that pluck was sending me back a list of undefined. Instead I had to do 2 plucks before instead of one, like the following.
var temp = _.pluck(users, 'facebook');
var arrayId = _.pluck(temp, 'id');
Thanks #ZenMaster for dropping the knowledge on the difference between _.without && _.difference. Your answer was correct, was pretty brain-dead after a binder and didn't see the obvious.
You don't need an _.toArray on the first argument of the without function
The second (and more) arguments to the without is not an array - it's a "list" of values.
The proper call would be:
var newArray = _.without(['1', '2', '3'], '1', '3');
which would result in:
['2']
In your case, you'd have to use _.difference as can be seen on JSFiddle here.
Here is the code:
var parsedID1 = [{id: '1', name: 'name1'}, {id: '2', name: 'name2'}];
var parsedID2 = [{id: '1', name: 'name1'}, {id: '3', name: 'name3'}];
var someIds = _.pluck(parsedID1, 'id');
var otherIds = _.pluck(parsedID2, 'id');
console.log(someIds, otherIds);
var newArray = _.difference(someIds, otherIds);
console.log(newArray);

sort javascript array in object, maintaining key

I have a javascript object with two array's as shown,
var Object = {'name': [Matt, Tom, Mike...], 'rank': [34,1,17...]};
I am trying to sort by rank 1,2,3.. but keep the name associated with the rank.
Object.name[0] // tom
Object.rank[0] // tom's rank of 1.
Should I reconfigure my object to make sorting easier?
I am currently using the
Object.rank.sort(function(a,b){return a-b});
to order rank, but the name does not stay with it.
All help appreciated. Thanks!
Yes, reconfigure. Say you had this instead:
var people = [{name:"Matt", rank:34}, {name:"Tom", rank:1}, {name:"Mike", rank:17}];
Then you could sort like this:
people.sort(function(a, b) {
return a.rank - b.rank;
}
Edit
Since you have parallel lists, just zip them together:
var people = [];
for (var i = 0; i < Object.name.length; i++) {
people.push({name:Object.name[i], rank:Object.rank[i]});
}
The real world object:
o = {name: ['Matt', 'Tom', 'Mike'], rank: [34,1,17]};
Make an array for better data structure:
var arr =[];
o.name.forEach(function(name, i){
arr.push({name: name, rank: o.rank[i]})
});
Sort by rank:
arr.sort(function(a,b){return a.rank - b.rank});
Sort by name:
arr.sort(function(a,b){return a.name- b.name});
Revert back to your original data structure:
o = {name:[], rank:[]}
arr.forEach(function(item){
o.name.push(item.name);
o.rank.push(item.rank);
});
Well, yes, if the i-th object in names array is connected to the i-th object in the rank array, you should represent it that way. This means, you should use a Person (or whatever it is) object with two properties: name and rank.
// person constructor
function Person(name, rank) {
this.name = name;
this.rank = rank;
}
// create the object with the array
var myObject = {
myArray: new Array()
};
// populate the array
myObject.myArray.push(new Person('Matt', 34));
myObject.myArray.push(new Person('Tom', 1));
myObject.myArray.push(new Person('Mike', 17));
// sort the Person objects according to their ranks
myObject.myArray.sort(function(a, b) {
return b.rank - a.rank;
});
You'll have to write your own sort function that for each sorting operation, remembers what index comes where per iteration in the ranks array. The do the same move from source index to destination index in the names array. (edit) One algortihm for this from the top of my head is the bubblesort, look it up.
The other option is to look for some kind of "map" collection implementation.

Categories

Resources