Array of objects in Javascript - using "push" - javascript

I am very new with Javascript and I can't seem to find an explanation for what is happening with my code.
I want to create an array of "people" where each person has some information associated with them, like "id" and "name". I don't know how many "people" I would need in my array so I am using "push" when I need another person. My problem is my array ends up filled with the last person's information.
Here is my declarations that I am using:
var ppl_arr = [];
var profile = {
id: 10000,
name: " ",
};
profile.id=3;
ppl_arr.push(profile); //add this person to my array
alert(ppl_arr[0].id + "\t" + ppl_arr.length);
profile.id=5;
ppl_arr.push(profile); // push next person to the array
alert(ppl_arr[0].id+"\t"+ppl_arr[1].id + "\t"+ppl_arr.length);
The first alert displays correctly : "3 1"
In the second alert, I get " 5 5 2" instead of " 3 5 2"
So I get two entries into my array but the second one seems to overwrite the first one. Can anyone explain what is happening?

You are simply changing the id of the same object, and adding the same object to the array twice. I would suggest that you create your 'people' objects as instance objects, something like this
//This is a constructor function for a Person object
function Person(id,name)
{
this.Id = id;
this.Name = name;
}
then
var ppl_arr = [];
ppl_arr.push(new Person(3,"Bob")); //add this person to my array
alert(ppl_arr[0].Id + " - " + ppl_arr.length); //outputs "3 - 1"
//NOTE put a string inbetween, because Id and length are both integers,
//you would actual get a sum of the two, not a string concatenation.
ppl_arr.push(new Person(5,"Steve")); // push next person to the array
alert(ppl_arr[0].Id+"\t"+ppl_arr[1].Id + "\t"+ppl_arr.length); // outputs 3 5 2

Question #1:
alert(ppl_arr[0].id + ppl_arr.length); will display the sum, not the concatenation - try alert(ppl_arr[0].id.toString().concat(ppl_arr.length));
Question #2:
You change the id property of an existing object, not copy it. So you change the id of the object already in the array as well. So you would need to
var ppl_arr = [];
var profile = {
id: 10000,
name: " ",
};
profile.id=3;
ppl_arr.push(profile);
//Create a new profile
var profile2 = {
id: 10000,
name: " ",
};
profile2.id=5;
ppl_arr.push(profile2);

Related

Javascript/Google Apps Script IndexOf issues [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 9 months ago.
Improve this question
There are a couple of similar queries here about the IndexOf function, but I'm reaching out because although the answers provided have been helpful, none of them have solved the issue.
I have a (very) large 2d array from a spreadsheet of names vs id codes. I read these values in apps script into an array (rIdr in the snippet below).
I then build 2x one-dimensional arrays so that I can use IndexOf to search for a name in the first array then use the returned index it to pull out the value from the second array.
var keys=[]; var vals=[];
//build key-val lookup arrays
for (var i = 0; i < rIdr.values.length; i++){
var k = rIdr.values[i][0].toString()
keys[i]=k
var v = rIdr.values[i][1].toString()
vals[i]=k
}
The name I'm looking for is obtained from a JSON which is populated elsewhere. I iterate over the names in this object, looking for them in my key and val arrays:
jsonobj.data.forEach(function(value) {
var idx = keys.indexOf(value.first_names_txt + " " + value.last_name_txt)
var id = -1;
if (idx > -1){id = vals[idx]}
Logger.log(value.first_names_txt + " " + value.last_name_txt + " " + id)
});
I've verified that both the name i'm pulling out of the JSON object as well as the elements of the keys array are String types. I've seen in the object inspector that the keys array is an array of strings (not, for example, an array of array objects).
Try as I might, i can't get IndexOf to return anything other than -1.
Even if I explicitly look for a name which I know is in there (and actually is a copy paste of the name as it's written on the sheet that I'm pulling values from), I still get -1 returned
var test
test = keys.indexOf("Joe Bloggs")
I'm tearing my hair out here. I don't want to write a separate function to match a name in the keys array, because I'll either need to pass in the full keys array as an argument, or make it a global variable - neither of which i want to do for various reasons.
Can anyone help with why IndexOf doesn't work here?
And if this is an issue that won't go away, is there a way to write my own search function which avoids passing large arrays around or declaring them as global variables?
Thanks all in advance
Description
I've constructed a spreadsheet sheet using the names from the json data file, randomized the names so they are no longer in alphabetical order and then assigned an id number to each.
The sample script I've provided lists the id number for the names in the json data file. Notice I'm working with the original data array. I don't need to create key value arrays to get the result I want. And I'm not checking if a name doesn't exist in the data array.
I've truncatd the json data for brevity
Code.gs
function test_json() {
try {
let jdata = {
"type" : "entrants",
"data" : [ {
"type" : "entrant",
"id" : "en_tdgwjajthr",
"first_names_txt" : "Archie",
"last_name_txt" : "White",
"entrytype" : "et_dv8u152j",
"answers" : {
"q_wg5qq6bgvsy90rh" : "Partenza Nude-Espresso RT"
}
}, {
.
.
.
.
}, {
"type" : "entrant",
"id" : "en_8uhauoe3jo",
"first_names_txt" : "Valentijn",
"last_name_txt" : "Brax",
"entrytype" : "et_dv8u152j",
"answers" : {
"q_wg5qq6bgvsy90rh" : "Dulwich Paragon CC"
}
} ],
"has_more_bool" : false
};
let values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test").getDataRange().getValues();
jdata.data.forEach(function(value){
let key = value.first_names_txt+" "+value.last_name_txt;
let found = values.find( row => row[0] === key );
console.log("key = "+key+" id = "+found[1]);
});
}
catch(err) {
console.log(err)
}
}
Execution log (abbreviated)
10:29:05 AM Notice Execution started
10:29:06 AM Info key = Archie White id = 21
10:29:06 AM Info key = ari panzer id = 15
10:29:06 AM Info key = Daniel Mulcahy id = 5
10:29:06 AM Info key = David Streule id = 12
10:29:06 AM Info key = Dominic Bell id = 10
10:29:06 AM Info key = Euan Davies id = 14

How can i add more values to my JSON file with fs?

I am making a Discord bot and I want to add JSON values like this
{
"Server ID": {
"01-Ticket": {
User: "Some ID",
Channel_ID: "Some ID"
}
}
}
I added one using fs but, when I add another, it deletes the first value ("01-Ticket")
This is my index.js:
channel.send(welcomeEmbed).then(async msg => {
await msg.react("🔒")
let tickets = require('./tickets.json')[msg.guild.id];
tickets[msg.guild.id]
console.log(tickets)
fs.writeFileSync('tickets.json', JSON.stringify(tickets, null, 5))
})
There are simply two things you need to do: create a new name for the ticket (if the previous one was "01-Ticket", then you need to name the new one "02-Ticket") and insert the ticket into the object using its new name.
A Solution
Here's a full example of how you could do such a thing:
let tickets = require('./tickets.json');
let newName = "01-Ticket";
if (msg.guild.id in tickets) {
let guildTickets = tickets[msg.guild.id];
let oldName = Object.keys(guildTickets).sort((a,b) => a.localeCompare(b)).pop();
let newNumber = Number(oldName.split("-")[0]) + 1;
let length = newNumber.toString().length;
newName = ("0" + newNumber).slice(-((length - 1) + Math.ceil(2 / length))) + "-Ticket";
}
else {
tickets[msg.guild.id] = {};
}
let ticket = {
User: msg.author.id,
Channel_ID: msg.channel.id
}
tickets[msg.guild.id][newName] = ticket;
fs.writeFileSync('tickets.json', JSON.stringify(tickets, null, 5))
Explanation
And below is the same code, but I've commented each new line to make it easier for you to understand the purpose of everything I am doing in this example:
let tickets = require('./tickets.json');
let newName = "01-Ticket";
//Check if the guild has any tickets
if (msg.guild.id in tickets) {
//The guild does already have tickets
//Get the tickets for this guild
let guildTickets = tickets[msg.guild.id];
//Take all of the ticket names ("01-Ticket", "02-Ticket", etc.) via Object.keys(),
//sort them in ascending numerical order via .sort(),
//and get the last one (the largest number, or the name of the latest ticket) via .pop()
let oldName = Object.keys(guildTickets).sort((a,b) => a.localeCompare(b)).pop();
//Take the old ticket's name ("01-Ticket"), get its number ("01"), and increment
//it by one (so now it would be "2")
let newNumber = Number(oldName.split("-")[0]) + 1;
//The length of the new number (for "2", the length would be 1)
let length = newNumber.toString().length;
//Now add a single "0" to the start of the name (name so far: "0")
//then add the new number (name so far: "02")
//Then, from the end of the name go back as far as necessary to get the proper name (name so far: "02")
//This works with all amounts of digits (ex: 2 -> "02"; 12 -> "12")
newName = ("0" + newNumber).slice(-((length - 1) + Math.ceil(2 / length))) + "-Ticket";
}
else {
//No tickets have been made in this guild yet
//So set the guild's ticket list to an empty object
tickets[msg.guild.id] = {};
}
//Create the new ticket to add to the guild's ticket list
let ticket = {
User: msg.author.id,
Channel_ID: msg.channel.id
}
//Add the ticket to the guild's ticket list
tickets[msg.guild.id][newName] = ticket;
//Update the tickets.json with your updated 'tickets' object
fs.writeFileSync('tickets.json', JSON.stringify(tickets, null, 5))
So first I am checking whether or not the guild's ID is already in tickets.json. If it isn't, we are adding it in as an empty object (and we add in the new ticket with the default name: "01-Ticket"). If the guild's ID is already in the file, then we need to create a new name for our new ticket. So first I get the object representing the guild's tickets. Then I get all of the keys in that object (which are the tickets' names: "01-Ticket", "02-Ticket", and so on). I sort those keys from least to greatest (since all of the ticket names begin with numbers, this is essentially sorting them numerically), and retrieve the last ticket name in the sorted list using .pop() (which is the ticket name starting with the largest number). I then take the number from that ticket name, and add one to it. Then I make sure to add a "0" at the beginning of the new ticket name if it is only one digit long; I am using a complex formula and .slice() to do so, but you could do this with a simple if statement. I then create the ticket itself, setting its user ID and channel ID properties. Finally, I add the ticket to the guild's ticket list by updating the tickets variable, and then update tickets.json with the new value of tickets.
The new name creation in this code is tested and works. The rest of the code is not tested, but works exactly the same as it does in some of my own bots' working code. If any part of this answer doesn't make sense or if you spot an error, feel free to comment it.

Errors while matching json objects based on similar object values

In my react app, I have two JSON objects that contain user quiz results. My goal is to generate a percentage value of how many answers each quiz in the roomSurveys has in common with the userSurvey answers using some sort of loop within a loop.
const [userSurvey, setUserSurvey] = useState({ "Q1":"A",
"Q2":"B, C, A",
"Q3":"C" });
const [roomSurveys, setRoomSurveys] = useState({
"user2":{ "Q1":"A",
"Q2":"B, C, C",
"Q3":"B" },
"user3":{ "Q1":"C",
"Q2":"B",
"Q3":"B" },
});
The function that calculates the answers in common would then update a state like this:
const [roomMatches, setRoomMatches] = useState({
"user2":{ "percentMatch":"1.0"},
"user3":{ "percentMatch": ".30"}
})
here is what I've got so far:
//loop through each user survey in the roomSurvey object
for (var key of Object.keys(roomSurveys)) {
var countSame;
var countTotal;
//loop through each user survey within the roomSurvey object
for (var key of Object.keys(roomSurveys[key])) {
//if answer matches userSurvey answer for the same key,
//add to count same and count total else, add to count total
if(roomSurveys[key] == userSurvey[key]){
countSame++;
countTotal++;
}else{
countTotal++;
}
console.log(key + " -> " + roomSurveys[key])
console.log(key + " -> " + userSurvey[key])
}
var percentMatched = countSame/countTotal;
setRoomMatches([...roomMatches, {key:{['percentMatch']: percentMatched}}]);
}
here are the errors I am getting:
In the second for loop, the roomSurveys[key] value is always undefined
roomMatches is not iterable (when trying to add new match percent to roomMatches state)
You have ovewritten your key variable int the second for loop. You need to name them key1 and key2 (or something more verbose)
You're using the same name for key variables, rename them and use them as desired.
... V
for (var survey of Object.keys(roomSurveys)) {
var countSame;
var countTotal;
v
for (var room of Object.keys(roomSurveys[survey])) {
...

Appending an object to a predefined array

I'm having trouble adding a new object to an array.
I have this function, addValue(shopItem, subTotal), where shopItem is a string and subTotal is an integer:
function addValue(shopItem, subTotal)
{
document.getElementById("extraSubHeader").innerHTML = "Current Total: " + subTotal + " Gold";
var object = {name: shopItem.name, description: shopItem.description}
alert("Bought " + shopItem.name + " for " + subTotal + " Gold.")
playerItems.push(object);
}
playerItems is an array of objects, by default it contains this:
playerItems = [
{ name: "Sword", description: "An old, rusty sword." }
];
However, when I try to add the new variable object (above), it instead wipes what I've already entered into the array and replaces it with whatever is in object.
EDIT: I've added a console.log(); to show the playerItems object, and it does in fact contain both objects. It must be a problem with how I iterate and display it. Thanks for everyone's help!

Accessing a associative array

Im trying to create a function that allows us to enter a persons name and their age. It will then be saved into an array.
var personnes=[];
function ajoutePersonne(n,a){
personnes["Nom"]=personnes.push(n);
personnes["Age"]=personnes.push(a);
personnes["Enfant"]="";
}
ajoutePersonne("Julie",100);
ajoutePersonne("Sarah",83);
ajoutePersonne("Jennifer",82);
ajoutePersonne("Olivia",79);
ajoutePersonne("Marge",55);
ajoutePersonne("Mathilde",48);
ajoutePersonne("Joanne",45);
ajoutePersonne("Isabelle",47);
ajoutePersonne("Celine",23);
ajoutePersonne("Caroline",29);
ajoutePersonne("Wendy",24);
ajoutePersonne("Kaliste",26);
ajoutePersonne("Karine",22);
ajoutePersonne("Sophie",28);
ajoutePersonne("Orianne",25);
ajoutePersonne("Alice",21);
print(personnes[1].Nom);
How come when im trying to access the 2 second person in the array under the category "Nom", Nothing shows up.
You need to put an entire object in the array, not push the name and age seperately:
var personnes=[];
function ajoutePersonne(n,a){
personnes.push({ "Nom" : n, "Age" : a, "Enfant" : ""});
}
personnes is an array, so in javascript it can only have integer indexes.
To do what I think you want to do:
function ajoutePersonne(n,a){
var person = {nom: n, age: a, enfant: ""};
personnes.push(person);
}
Where "person" is a javascript object using JSON.
Arrays are only meant to store numeric indices, you can create members like Nom but these will in no way react like a normal numeric index.*
Either use an object, or push objects into your array.
var personnes=[];
personnes.push({ "Nom" : "Julie", "Age" : 100 });
personnes[0].Nom // -> Julie
or
var personnes={};
personnes["Julie"] = 100;
// equal to:
personnes.Julie = 100;
or
var personnes={};
personnes["Julie"] = {"age":100 /*,"more attributes":"here"*/}
However, the last two notations assume that the names are unique!
*You can do the following:
var ar = [];
ar.attr = 5;
ar.attr; // -> 5
ar.length; // -> 0, since attr is not enumerable
// also all other regular array operation won't affect attr

Categories