Multiple triggers "case"s in an array [duplicate] - javascript

This question already has answers here:
Switch statement for multiple cases in JavaScript
(26 answers)
Closed 7 years ago.
var message = "hello [[xxx]] bye [[ZZZ]]"
var result, re = /\[\[(.*?)\]\]/g;
while ((result = re.exec(message)) != null) {
switch (result[1].toLowerCase()) {
case "xxx":
console.log("found xxx");
break;
case "zzz":
console.log("found zzz");
break;
}
}
This is an example of the code im using, currently it will output
found xxx
found zzz
Is there a way to put multiple ways to "trigger" a case? such as
case "xxx", "aaa", "bbb":
console.log("found 3xletters");
break;
I've tried this ^^^ but only the last thing can trigger it, so in the above case xxx and aaa wont trigger, but bbb will

Yes, you can do this, but I would not recommend it if you have very many alternatives per case. In switch statements break ensures that the program exists the switch statement rather than continuing on to the following cases. So, if you want to check for multiple cases, you can simply leave break out of all but the last one, like so.
...
switch (result[1].toLowerCase()) {
case "aaa":
case "bbb":
case "xxx":
console.log("found aaa, bbb, or xxx");
break;
case "zzz":
console.log("found zzz");
break;
}

Related

JavaScript RegEx: How do I utilise named capture groups? [duplicate]

This question already has answers here:
Javascript: Named Capture Groups
(2 answers)
Named capturing groups in JavaScript regex?
(10 answers)
Closed last month.
I am currently working at a Plugin for RPG Maker MZ and for that, i learned how to use RegEx for analyzing the Content of a Notetag. While my first try with them was actually pretty good, i assume it didn't used the full potential of RegEx and because i need to expand the my RegEx anyway so the user has more options, i wanted to try out named capture groups for better readability and easier access for me as a developer.
Unfortionatly, i wasnt able to find out how to get the "group" object of the objects i got from the Iterator from matchAll(). So my question would be how to analyse the content of a named capture group in javascript.
Important: as far as i saw, the other questions didnt answer the question why i wasnt be able to find the right group object. also, most of the answers are with the exec function instead of the matchAll function.
The for this part relevant Code is:
const regex1new = /(?<ItemCategory>Item|Armor|Weapon)\s*:\s*(?<ID>\d+)\s*(?<Weight>w:(?<WeightFactor>\d+))?/gm;
let foundTagEntrysList = Array.from(this.enemy().meta.HellsCommonDropList.matchAll(regex1new), entry => entry[0]); //If you wanna reproduce this, just replace this.enemy().meta.HellsCommonDropList with a string
newTagsAnalyser();
function newTagsAnalyser() {
foundTagEntrysList.forEach(matchedElement => {
let Item;
let Weight;
let ID = matchedElement.groups.ID;
switch (matchedElement.groups.ItemCategory) {
case "Item":
Item = $dataItems[ID];
break;
case "Weapon":
Item = $dataWeapon[ID];
break;
case "Armor":
Item = $dataArmor[ID];
break;
default:
break;
}
if (typeof matchedElement.groups.Weight !== 'undefined'){
Weight = matchedElement.groups.WeightFactor;
}
commonItemDataMap.set(Item, Weight);
});
}
What did i expected?
That the matechedElement.group.xxx returnes the content of the group that is named xxx.
What was the result?
rmmz_managers.js:2032 TypeError: Cannot read property 'ID' of undefined

Using if/else vs. switch

I'm wondering if it would be better to use a switch statement in my specific case.
I'm writing an Alexa Custom Skill, and I need to "redirect" to the appropriate intent depending on the available information (aka slots). Below is what I have currently (using if/else):
if (_type === "IntentRequest") {
this.handler.state = states.START;
if (_slots.indexOf("address") != -1) {
this.emitWithState("GoingToAddressIntent");
} else if (_slots.indexOf("place") != -1) {
this.emitWithState("GoingToPlaceIntent");
} else if (_slots.indexOf("type") != -1) {
this.emitWithState("GoingToTypeIntent");
} else if (_slots.indexOf("purpose") != -1) {
this.emitWithState("GoingToPurposeIntent");
} else {
this.emit("Unhandled");
}
}
I expect _slots to be an array of any permutations of the four elements, [ "address", "place", "type", "purpose" ]. Therefore, it could be anything from [ "address" ] to [ "place", "purpose" ] to etc. etc., but always in the same order (e.g. [ "purpose", "address" ] would never happen).
The order of the comparisons matters because there is a "hierarchy" of information; so if the "address" slot is present, I have to emit the "GoingToAddressIntent" regardless of what other slots are available. Given this requirement, I thought using a switch statement maybe more straightforward and readable despite having to have a few extra lines of code to "convert" the array of strings to an array of booleans. It clearly lays out the hierarchy & make sure they are evaluated in order. I could do:
if (_type === "IntentRequest") {
this.handler.state = states.START;
slots = [
_slots.indexOf("address") != -1,
_slots.indexOf("place") != -1,
_slots.indexOf("type") != -1,
_slots.indexOf("purpose") != -1
]
switch(slots.indexOf(true)) {
case 0:
this.emitWithState("GoingToAddressIntent");
break;
case 1:
this.emitWithState("GoingToAddressIntent");
break;
case 2:
this.emitWithState("GoingToTypeIntent");
break;
case 3:
this.emitWithState("GoingToPurposeIntent");
break;
default:
this.emit("Unhandled");
}
}
... in which case I have an extra line to define the array of booleans, use indexOf() to get the index of the first occurrence of a true literal (because all 4 slots are always in the order of hierarchy), and run it through the switch statement. However I wanted ask experts on their ideas of what best programming practice is in this case and the reasoning behind it because I want this to become a long-term project that is maintainable, and also I believe I can learn something from their insights.
Please leave a comment if you think this should be migrated to another community on SE, but from my research (although 3 years old) I believe this should be fine (I'm just not 100% confident on this).
If they're always in the order of precedence in _slots, maybe you could make a hash map to the state you're going to emit...
const map = {
address: "GoingToAddressIntent",
place: "GoingToPlaceIntent",
type: "GoingToTypeIntent",
purpose: "GoingToPurposeIntent"
};
const state = map[_slots[0]];
if (state) {
this.emitWithState(state);
} else {
this.emit("Unhandled");
}
I wouldn't go with your example of the switch statement. People could understand what you're attempting to do, but it does seem pretty convoluted. I use switch statements pretty liberally, mostly in backend code, and I think it could work fine here. A group of if/else is fine too, since there's only 4 cases you need to work through. Lets roll with the switch statement since that's what you're asking about.
Based on your explanation, the order is always going to be the same, although the first value you get may be different. So the solution would be to simply grab the first value, and switch over that.
if (!!slots.length) {
var keyword = slots[0];
switch (keyword) {
case 'address':
this.emitWithState("GoingToAddressIntent");
break;
case 'place':
this.emitWithState("GoingToPlaceIntent");
break;
case 'type':
this.emitWithState("GoingToTypeIntent");
break;
case 'purpose':
this.emitWithState("GoingToPurposeIntent");
break;
default:
this.emit('Unhandled'); // I typically throw an exception here
}
}

Is It Possible to Generate Case Statements with a Loop?

I have a script in my project that will generate notifications, though, these notifications thus far have the same title and description through their pre-defined variables:
notificationTitle: "Notification",
notificationDescription: "This is a notification.",
This is rather boring, really. And whilst I can go and set the amount of notifications* I want the script to generate, along with enough case statements to facilitate them, this is not reasonable. In the environment where we intend to have multiple different notifications for multiple different users, I don't want to have to write a case statement for each one, like so:
function setNotificationDescription(iteration) {
"use strict";
switch (iteration) {
case 1:
values.notificationDescription = "One";
break;
case 2:
values.notificationDescription = "Two";
break;
case 3:
values.notificationDescription = "Three";
break;
case 4:
values.notificationDescription = "Four";
break;
case 5:
values.notificationDescription = "Five";
break;
case 6:
values.notificationDescription = "Six";
break;
default:
values.notificationDescription = "Seven";
}
}
*This would be filled by a count of objects in a JSON file in the future, but for my example I set it myself.
Live Example: http://moonsquads.com/scriptbase/notification-generation/
Is there a way to generate these case statements automatically?
Instead of setting the values.notificationDescription inside the function, I have moved it outside for demonstration purposes (compare the "case-version" with the "array-version"):
https://jsfiddle.net/6j98sxue/1/
This avoids switch-cases by using an array since numeric index is concerned, and avoids a big change to your original code.
In addition to the above, I would suggest a Code Review post and people there would give detailed comments on refactoring the existing code. Modifying the value object and getting values from it will cause problem, e.g. it is hard to test the code as we cannot do dependency injection.

indexOf within Switch

I have a Javascript-based bot for a Xat chatroom which also acts as an AI. I've recently decided to redo the AI part of it due to it becoming an absolutely massive chain of else if statements, becoming nearly impossible to work with.
I did some research and came up with a new idea of how to handle responses. I'll give you the code segment first:
function msgSwitch(id,msgRes) {
var botResponse = [];
switch (msgRes) {
case (msgRes.indexOf("hi") !=-1):
botResponse.push("HELLO. ");
case (msgRes.indexOf("how are you") !=-1):
botResponse.push("I AM FINE. ")
case (msgRes.indexOf("do you like pie") !=-1):
botResponse.push("I CAN'T EAT. THANKS, ASSHAT. ")
default:
respond (botResponse);
spamCount(id);
break;
}
}
The idea here is to check msgRes (the user's input) and see how many cases it matches. Then for each match, it'll push the response into the botResponse array, then at the end, it'll reply with all the messages in that array.
Example
User Msg: Hi! How are you?
msgRes: hi how are you
Bot Matches:
hi > pushes HELLO. to array
how are you > pushes I AM FINE. to array
Bot Responds: HELLO. I AM FINE.
This in turn saves me the trouble of having to write an if for each possible combination.
However, after looking into it some more, I'm not sure if it's possible use indexOf inside of a switch. Does anyone know of a way around this or have a better idea for handling responses in the same manner?
EDIT:
To Avoid the XY Problem (To clarify my problem)
I need a clean alternative to using a massive chain of else if statements. There are going to be hundreds of word segments that the bot will respond to. Without the ability for it to keep searching for matches, I'd have to write a new else if for every combination.
I'm hoping for a way to have it scan through every statement for a match, then combine the response for each match together into a single string.
EDIT 2:
I should also add that this is being ran on Tampermonkey and not a website.
you just need to compare to true instead of msgRes (since cases use === comparison), and use break to prevent the annoying fall-though of the switch behavior:
function msgSwitch(id,msgRes) {
var botResponse = [];
switch (true) {
case (msgRes.indexOf("hi") !=-1):
botResponse.push("HELLO. "); break;
case (msgRes.indexOf("how are you") !=-1):
botResponse.push("I AM FINE. "); break;
case (msgRes.indexOf("do you like pie") !=-1):
botResponse.push("I CAN'T EAT. THANKS, ASSHAT. "); break;
default:
respond (botResponse);
spamCount(id);
break;
}
}
This is a perfectly valid logical forking pattern, known as an "overloaded switch". A lot of folks might not realize that each case: is an expression, not just a value, so you could even put an IIFE in there if needed...
My two cents for the gist of what you're trying to do:
function msgSwitch(id, msgRes) {
var seed = {'hi': 'HELLO. ', 'how are you': 'I AM FINE'};
var botResponse = [];
for (var key in seed) {
if (msgRes.indexOf(key) !== -1) {
botResponse.push(seed[key]);
}
}
}
In my opinion it is easier to change this program as you only have to edit the seed if you have more responses in the future. You can even stash the seed on some json file and read it (via ajax) so the program does not need to be changed if there are additional messages.

How to shorten a long if else statement [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I'm trying to figure out how I can streamline a possible long if else statement.
There are 8 possibilities that can be chosen and for each option 1-8 I want to display a message.
For example this is what works but I know can be writtern much better:
if(this.cv == '1'){
console.log('Greater Then 1');
} else
if(this.cv == '2'){
console.log('Greater Than 2');
}
etc...
Looking for something a little more dynamic.
Use a map:
var messages = {
'1' : 'Greater than 1',
'2' : 'Greater than 2',
....etc
}
console.log(messages[this.cv]);
If that is the exact format of your message (for all cases), then you could simply write:
console.log('Greater Than ' + this.cv);
However, if you need more flexibility with each case, then you can use a switch statement as other answers have suggested.
Use a switch statement:
switch(this.cv)
{
case '1':
console.log('Greater Than 1');
break;
case '2':
console.log('Greater Than 2');
break;
default:
//executed if no matches are found
}
Or a map would work also work well per adeneo's answer, since that is essentially how a switch statement is implemented. Both are good options for compressing several if-statements.
This is what the switch statement was made for.
switch(this.cv) {
case '1':
console.log("Greater than 1");
break;
case '2':
console.log("Greater than 2");
break;
}
You can even add a "catch-all" default action:
default:
console.log("I don't know what to do with "+this.cv);
switch(n)
{
case '1':
execute code block 1
break;
case '2':
execute code block 2
break;
default:
code to be executed if n is different from case 1 and 2
}
You can use a switch statement , check this link for more details
Genaral Syntax of SWITCH:
switch (expression) {
case label1:
statements1
[break;]
case label2:
statements2
[break;]
...
case labelN:
statementsN
[break;]
default:
statements_def
[break;]
}
In your case :
switch(this.cv) {
case '1':
console.log("Greater than 1");
break;
case '2':
console.log("Greater than 2");
break;
}
I'd say create an object that maps the possible values to messages and simply retrieve the message from the map like so:
var messages = {'1': 'Greater Then 1',
'2': 'Greater Than 2'};
console.log(messages[this.cv]);
depends sometimes i have many functions to add to various variables ..
in that case i prefer to use something like that.
i create an object with the answers. then i check if the answer exists and execute it.
i prefer that over switch
var a={'2':'greater than 2','1':'greater than 1'}
console.log(a[this.cv]?a[this.cv]:'')
another way to write this is
var a={'2':'greater than 2','1':'greater than 1'}
!a[this.cv]||(console.log(a[this.cv]));
or if you just have to do a short check i use javascript shorthand.
console.log('Greater then '+(a=this.cv,a==1)?1:(a==2)?2:'whatever');
or
console.log('Greater then '+(this.cv==1?1:2));
and in your case a
console.log('Greater than '+this.cv);
should be enough.

Categories