Using strings to improve efficiency of a JavaScript - javascript

I'm writing a plugin for an open source utility in JavaScript, where the module I'm writing will interact with an audio interface. I've started coding functionality of some mutes. Instead of writing 32 separate pieces of code I'd like to use a variable to identify the channel that has been changed. For example:
if (address.match('/flx_mute/1')) {
var mutestatus = message.args[0].value;
if (mutestatus === 1) {
this.flexmute1 = "Muted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
} else {
this.flexmute1 = "Unmuted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
}
}
I know in other languages I could write something like this:
let i = ""
// Code here to determine the channel that needs its mute status changed...
let flexchannelmute = "flexmute" + i
if (mutestatus === 1) {
this.[flexchannelmute] = "Muted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
} else {
this.[flexchannelmute] = "Unmuted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
}
The first question is what is this kind of string substitution called? Secondly, is what I'm describing possible?

You can create an object (flexChannels) and a ternary statement to store the current status.
let flexChannels = {};
let mutestatus = 1;
let i = 1;
let flexchannelmute = "flexmute" + i
flexChannels[flexchannelmute] = (mutestatus === 1) ? "Muted" : "Unmuted";
console.log(`Flex Channel ${i} is: ${flexChannels[flexchannelmute]}`);

I could not make out exactly what you are trying to do, but you can try this.
In your top level you appear to be detecting if a message was sent to a particular address.
I assume that the part after the first slash denotes that the message is related to the mutes in question and that the number after the second slash is number of the mute the message is for.
You can use a regex to match this and get the required info.
The method of accessing a property on an object using a variable as the key is called "bracket notation".
const addressRegex = /\/flx_mute\/(\d+)/; // Matches "/flx_mute/" followed by a number
const matchResult = address.match(addressRegex);
// If a match was found...
if (matchResult) {
const muteStatus = message.args[0].value;
const muteNumber = matchResult[1]; // This is the number in the address.
const muteName = "flexmute" + muteNumber;
if (muteStatus === 1) {
this[muteName] = "Muted";
console.log(`Flex Channel ${muteNumber} is: ${this[muteName]}`);
} else {
this[muteName] = "Unmuted";
console.log(`Flex Channel ${muteNumber} is: ${this[muteName]}`);
}
}
You can simplify the code inside the if block by using a ternary expression and a temporary variable:
if (matchResult) {
const muteStatus = message.args[0].value;
const muteNumber = matchResult[1];
const muteName = "flexmute" + muteNumber;
const muteState = muteStatus === 1 ? "Muted" : "Unmuted";
this[muteName] = muteState;
console.log(`Flex Channel ${muteNumber} is: ${muteState}`);
}

Related

Doing an addition from a JSON value which is a number and replace it by the result

I need to manipulate a JSON value which is a number.
I tried this, but without any result:
let picture = require('./pictures.json');
let embed = new Discord.MessageEmbed()
.setColor('#fdafb5')
.setDescription(picture['pic01'].description)
.addField("❤ Likes:", picture['pic01'].likes)
.setImage(picture['pic01'].image)
.setFooter("Source: " + picture['pic01'].source)
.setTimestamp()
let authorCommandMessage = message.author.id;
message.channel.send(embed).then(message => {
message.react('❤');
message.awaitReactions((reaction, user) => user.id === authorCommandMessage && (reaction.emoji.name === '❤'), { max: 1, time: 30000 })
.then(collected => {
if(collected.first().emoji.name === '❤'){
picture['pic01'].likes + 1;
}
});
});
}
(Here's the JSON if needed:)
{
"pic01":
{
"likes":0,
}
}
Simon Cheng's answer is correct, assignment is necessary.
// Assign +1 value to the current property.
picture['pic01'].likes += 1;
// This will do the same as above, but less elegantly.
picture['pic01'].likes = picture['pic01'].likes + 1;
Here's a simple JSFiddle showing how it works.
I noticed you're doing this assignment inside a possibly asynchronous routine. Please keep in mind that the side effect of changing the likes property will only happen after this routine does what it needs to do, and you must read the object after it completed.
And, just to be sure, if you're trying to change the JSON file itself, you'd need to add a read/write mechanic. Currently, you're reading the JSON file and creating a copy of it as a JS Object inside your runtime - therefore, changes made to this copy will not affect the JSON file.
you need to assign the calculated value back to the json.
change
picture['pic01'].likes + 1;
to
picture['pic01'].likes = picture['pic01'].likes + 1;
or even better,
picture['pic01'].likes += 1;
I found how to resolve my problem (thanks to mdeamf for telling me that I need to write the file and Simon Cheng for telling me how to do the addition).
let picture = require('./pictures.json');
let pictures = ['pic01'];
let random = Math.floor(Math.random() * pictures.length);
let embed = new Discord.MessageEmbed()
.setColor('#fdafb5')
.setDescription(picture[pictures[random]].description)
.addField("❤ Likes:", picture[pictures[random]].likes)
.setImage(picture[pictures[random]].image)
.setFooter("Source: " + picture[pictures[random]].source)
.setTimestamp()
let authorCommandMessage = message.author.id;
message.channel.send(embed).then(message => {
message.react('❤');
message.awaitReactions((reaction, user) => user.id === authorCommandMessage && (reaction.emoji.name === '❤'), { max: 1, time: 30000 })
.then(collected => {
if(collected.first().emoji.name === '❤'){
picture[pictures[random]].likes = picture[pictures[random]].likes += 1;
fs.writeFileSync('pictures.json', JSON.stringify(picture, null, 2));
}
});
});

Automatically create variable names from results?

I'm trying to figure out how optimize my code away from countless if/else statements.
My current code is:
jQuery.each(val, function (i, data) {
//Secret Rare
if(data.card_variations[0].card_rarity == 'Secret Rare'){
secretcount++;
jQuery('.secret-cards').append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
}
//Ultra Rare
if(data.card_variations[0].card_rarity == 'Ultra Rare'){
ultracount++;
jQuery('.ultra-cards').append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
}
//Super Rare
if(data.card_variations[0].card_rarity == 'Super Rare'){
supercount++;
jQuery('.super-cards').append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
}
//Rare
if(data.card_variations[0].card_rarity == 'Rare'){
rarecount++;
jQuery('.rare-cards').append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
}
//ShortPrint
if(data.card_variations[0].card_rarity == 'Short Print'){
shortprintcount++;
jQuery('.shortprint-cards').append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
}
//Common
if(data.card_variations[0].card_rarity == 'Common'){
commoncount++;
jQuery('.common-cards').append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
}
});
As you can see, this is a mess of if/else statements checking for specific rarities and appending to a div depending on the current rarity. There are over 25 different rarities so I figured I can't keep going this way and I'd also need to accommodate every rarity going forward manually through code. I'm also running a count for each to output how many they are.
Is there an optimal way of assigning variables for the counters and dynamically create div class names depending on the result?
EDIT: Maybe an optimal method would be creating an array of all rarities. Since this would still require manual updating, maybe I can query the database through PHP to get all rarities and then fill this array...
Since in the browser var x = 1 is equal to var window.x = 1, you can use the global object to create dynamic variable names.
var rarityName = data.card_variations[0].card_rarity;
window[rarityName] = window[rarityName] ? window[rarityName] + 1 : 1;
But it's probably better to just create a scoped object, that will store the count for you.
var counts = {}; // declare once in global scope somewhere first
//
var rarityName = data.card_variations[0].card_rarity;
counts[rarityName] = counts[rarityName] ? counts[rarityName] + 1 : 1;
So it will be something like this:
var counts = {};
jQuery.each(val, function (i, data) {
var rarityName = data.card_variations[0].card_rarity;
counts[rarityName] = counts[rarityName] ? counts[rarityName] + 1 : 1;
var friendlyClassName = "." + rarityName.toLowerCase().split(" ").join("-");
jQuery(friendlyClassName).append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
});
You could use a dictionary to keep track of the counts and use the rarity as the key. You could also cut out on a lot of code repetition if you change your classes to match the rarity too.
counts = {
"Secret Rare": 0,
"Ultra Rare": 0,
"Super Rare": 0,
"Rare": 0,
"Short Print": 0,
"Common": 0
}
jQuery.each(val, function (i, data) {
let rarity = data.card_variations[0].card_rarity;
let className = rarity.toLowerCase().replace(" ", "-");
counts[rarity] += 1;
jQuery(className).append('<figure><img src="'+data.card_img+'" title="'+data.card_name+'" alt="'+data.card_name+'"><figcaption>'+data.card_variations[0].card_code+'<figcaption></figure>');
});
Could you build a map object? The key would be the card_rarity name and the value would be {element, count}. A map.has(key) will check if it already exists - if it does, get the {element, count} value, extract the element name, update the count value and then use map.set(key, {element, count}) to update the map. If the key doesn't exist, create a new one.
You would still need to manually create the elements that you are appending the data onto - though you could, perhaps, automate the creation of those as well if it is a new key?

Im making a personality quiz and need to convert answer codes to a word

I'm trying to make a personality quiz and I want to convert the answer code I got (yes is an A and no is a B) its a simple 4 question personality quiz for kids. I have a function that puts all 4 questions "identifiers" (the A and B) into a string then I want to make an if statement that tells the program to output an answer based on that 4 letter code. So basically when it is AAAA the program needs to convert that to a Leopard(AAAA = Leopard) I have the code that outputs it to the HTML file I just need to convert that AAAA to a word.
function getEndingSentence() {
var quizRadio = document.getElementsByName("rq");
var answerCode = ''; //It's easier to handle if we simply merge all sentences into a string
for (var i = 0; i < quizRadio.length; i++) {
if (quizRadio[i].checked) {
answerCode += quizRadio[i].getAttribute("data-endingsentence"); //these are the attributes used to generate quiz answers
}
}
return answerCode;
}
function getAnswer() {
var finalAnswer = ''
var preAnswer = getEndingSentence();
if (preAnswer = "AAAA") {
finalAnswer = 'Jagluiperd'
} else {
finalAnswer = 'Undefined'// just to test if the if statment works
}
return finalAnswer;
}
function setEndingSentence() {
var personalityResults = getAnswer();
document.getElementById("results_screen").className = "";
document.getElementById("generated_text").innerHTML = personalityResults;
}
You could create an enumeration.
const answerMap = {
AAAA: 'First result',
AAAB: 'Second result',
...
};
function getAnswer() {
return answerMap[getEndingSentence()];
}
You may want to add a guard against invalid values, but this should do the trick.
getEndingSentence() returns for example 'AAAA' and answerMap['AAAA'] returns 'First result'.
Another option would be to use a switch statement: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Sentencias/switch
But I think an enumeration works better.
I'm assuming you want a way to do this for multiple results cause as it is your code shoud be working. If you want to convert a key into a defined value you could use an object to avoid multiple if conditions.
const quizResults = {
'AAAA': 'Leopard',
'AAAB': 'Lion', // ..and so on for each case
}
function getAnswer() {
var preAnswer = getEndingSentence();
return quizResults[preAnswer];
}

nodejs javascript find with condition

Hello I have a queue of players and wanted to get the first player that met one of my two conditions, but I am unsure how to do that.
First I get the value of a player (mmr)
and wanted to get one (only one) player from the queue that had 5% more or less of this value
My condition I think is this to get 5% more or less:
const condition = (5/100)*playerOne.mmr + playerOne.mmr
const condition2 = (5/100)*playerOne.mmr - playerOne.mmr
my function:
makeMatch(playerOne) {
// make matched players
const condition = (5/100)*playerOne.mmr + playerOne.mmr
const condition2 = (5/100)*playerOne.mmr - playerOne.mmr
const player = playerOne;
const matchedPlayer = this.players.find();
// remove matched players from this.players
this.removePlayers(matchedPlayers);
// return new Match with matched players
return new Match(matchedPlayers);
}
I have questions as I would get 5% more or less within my find
Check out the documentation for the find function it details this use case. Here's the line that you would want for the desired result.
const matchedPlayer = this.players.find((playerTwo) => playerTwo.mmr > condition || playerTwo.mmr > condition2);
You can try something like this:
if (player.condition1 > condition1*0.95 && player.condition1 < condition1*1.05) {
// then you keep the player
} else {
// else you remove it from the list
}
Also, I would highly reccomend you to give better identifiers to the variables. Instead of condition1, something like age, height, weight.

How to pick random element in an array AVOIDING (EXCEPT if it's) a certain value?

For example, when users are connecting to this application they are given a userid var, then it's inserted into the array. So, i'm using
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
to pick another random user. But i need to make sure it doesn't pick the userID they personally were assigned so they don't end up getting themselves.
how would i use that code but tell it to "remember, make sure you don't pick userid"
maybe I could do something like
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
if (chosenUser = userid)
{
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
} else
{
//next part of mycode
}
Maybe that should be a while (chosenUser = userid) incase it gets it twice...
But, i'm thinking i could skip all that if there is a efficent way just to make sure it doesn't pick it in the first place.
Sorry, i'm not quite sure how I should have phrased the question or if there is a term i'm unaware of to refer to what i'm trying to do.
using Math.round() can lead to returning "undefined" since you're allowing it to choose usersOnlineArray.length, which is not indexed. use Math.floor() instead.
you could move the item you don't want to match to the end of the array and then select at random an element from the array except for the last element:
//Users Array
var usersArray:Array = new Array("JoeID", "MaryID", "UserID", "JohnID", "SusanID");
//Find UserID And Push It To The End
usersArray.push(usersArray.splice(usersArray.indexOf("UserID"), 1));
//Randomly Select Companion From usersArray Except For UserID (Last Element)
var companion:String = usersArray[Math.floor(Math.random() * (usersArray.length - 1))];
trace(companion);
You are on good way, just call again your method for example
public void Something(){ string user = GetUser(); }
public string GetUser(){
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
if (chosenUser == userid)
{
return GetUser();
}
return chosenUser;
}
Since Flash is same ECMA branch of languages as JavaScript and there is not a JS answer (and ActionScript is kind of extinct species) here is the answer (without recursion) in JS:
var getRandomExcept = function(elements, exceptElement){
if(elements.length <= 0){
return null;
}else if(typeof exceptElement !== 'undefined' && elements.length == 1){
if(elements[0] === exceptElement) return null;
}
var n = Math.floor(Math.random() * elements.length);
if(elements[n] === exceptElement){
// make one random trip around elements but stop (<elements.length) before the exceptElement
n = (n + Math.floor(Math.random() * elements.length)) % elements.length;
}
return elements[n];
};

Categories