Dynamic Switch in Javascript - javascript

I want to do a switch with dynamic content in javascript, I will put an example:
switch(terrain) {
case "Plains":
terrain = Plains.create(newPosition);
break;
case "Mountains":
terrain = ImpassableMountain.create(newPosition);
break;
case "Hills":
terrain = Hills.create(newPosition);
break;
case "Forest":
terrain = Forest.create(newPosition);
break;
case "River":
terrain = River.create(newPosition);
break;
default:
};
So if I want to add a new Terrain for example Ocean, I want that will be updated automatically. I am thinking about to put all the terrains in a array
var terrainArray = ["Plains","Mountains","Hills","Forest","River","Ocean",...]
But I don't know how to put that in a switch in the most optimized way because if I try
for(var i=0;i<terrainArray.length;i++){
if(terrain==terrainArray[i]){
Terrain.create(newPosition);
}
}
It wouldn't be optimized because it will go through the entire array.
Also I need to put the class dynamically so if that terrain is Plains I need to put Plains.create instead of other, maybe can I do that with an array of classes?

Use an object literal - that makes it much easier and faster as you don't have to loop the array everytime you lookup something. It's also easier to handle dynamically than a switch
const foo = {
Plains: Plains,
Mountains: ImpassableMountains
}
let x = 'Plains';
foo[x].create(newPosition)

You can simply use .indexOf to check if it's in that array and perform actions accordingly.
terrainArray.indexOf(terrain) >=0 ? Terrain.create(newPosition) : null;
To
it will go through the entire array., To find something in array it will.. always

Related

Which approach is better for assigning conditionally?

Below code is just initializing two variables, depending on cloudType passed, which can be assigned by either of approaches. In JavaScript less number of lines of code is recommended so I like the second approach also it removes duplication.
Approach one gives me flexibility to add operations in specific case if required in future where as 2nd approach is saving me good amount of bytes also helping me reduce duplication.
switch (cloudType) {
case "aws":
value = this._resetMessageDefaultValues.aws
resetText = this._messages.current.aws
break;
case "private":
value = this._resetMessageDefaultValues.private;
resetText = this._messages.current.private
break;
case "azure":
value = this._resetMessageDefaultValues.azure;
resetText = this._messages.current.azure
break;
}
Or
value = this._resetMessageDefaultValues[cloudType];
resetText = this._messages.current[cloudType]
By all means, I prefer the second code.
If your cloudType variable has a one-to-one mapping to properties of those two other objects, why not make it clear? This also avoids duplicate code.
To be safe, add these checks to your code:
value = this._resetMessageDefaultValues[cloudType];
resetText = this._messages.current[cloudType]
if (typeof value == "undefined" || typeof resetText == "undefined") {
// throw some error
}
This way you'll know that when a new cloudType is added to your system, you should add relevant properties to those other objects.
Amplifying #Mohammad's answer
The second code is already industry standard of referring to object properties through its keys via brackets foo['bar']. If you want to add extra operations, just put in the switch case block below. Still saving you a few bytes than the first solution you wrote
value = this._resetMessageDefaultValues[cloudType];
resetText = this._messages.current[cloudType];
switch (cloudType) {
case "aws": break;
case "private": break;
case "azure": break;
}
Considering the keys truly matches directly to the cloudType variable, and even if it isn't, I advise matching it.

how to put a switch in a variable in javascript?

I'm making a little mini game and I have to put multiple switches inside of themselves, so I really need to know how to put a switch into a few words so I can make this game. I have tried it so that it's fully written out but it takes FOREVER and it is very confusing as to what is what. please help!
EDIT: im sorry i made this so confusing... let me say that again in english (: what i need to do is make it so when they either choose one of the cases or if they choose none of them (default) it would reactivate the switch. the way the person would choose is through a prompt. so what i thought i could do was make a switch into a variable then use that variable inside the switch basicly creating an endless thing that if they choose default it asks them again. here is an example i will post it in one minute
here you go!:
//this is the variable holding the switch
/*I I I I I*/
/*V V V V V*/
var switch1 = {
var choice = prompt("do you choose EXAMPLE or EXAMPLE").toUpperCase()
switch(choice) {
case 'EXAMPLE':
//this will repeat the whole prompt
switch1
break;
default:
//this will repeat it too
switch1
break; }
}
So how would i do this and make java accept this #ajaysinghdav10d?
JavaScript allows you to nest switch statements.
Have a look at this dummy example in which a service returns the location of the customer and his choice of product. Based on the combination of Choice and Location, a function to return the co-ordinates of the nearest store is called; I have used dummy values where ever necessary and alerts to explain the flow of control within the nested switch statements:
var choice = "CHO2"; /* call getChoice() function returning values from {CHO1, CHO2, ...}*/
var location = "LOC1"; /*call getLocality() function returning values from {LOC1, LOC2, ...}*/
switch (location) {
case "LOC1":
switch (choice) {
case "CHO1":
/* redirectToCHO1ofLOC1() is a function returning co-ordinates of the store*/
alert("redirectToCHO1ofLOC1");
break;
case "CHO2":
alert("redirectToCHO2ofLOC1");
break;
default:
alert("redirectToRegret");
break;
}
break;
case "LOC2":
switch (choice) {
case "CHO1":
/* redirectToCHO1ofLOC2() is a function returning co-ordinates of the store*/
alert("redirectToCHO1ofLOC2");
break;
case "CHO2":
alert("redirectToCHO1ofLOC2");
redirectToCHO2ofLOC2();
break;
default:
alert("redirectToRegret");
break;
}
break;
default:
alert("redirectToRegret");
break;
}
Updated answer based on the new context :
You must use recursion for that matter. Put your switch inside a function and call that function from the case statement of your switch, please have a look at this:
function recursiveSwitch() {
var choice = prompt("do you choose EXAMPLE or EXAMPLE").toUpperCase()
switch (choice) {
case 'EXAMPLE':
//this will repeat the whole prompt
recursiveSwitch();
break;
default:
//this will repeat it too
recursiveSwitch();
break;
}
}
Now just call the recursiveSwitch function from where ever you want and an endless loop would start.

javascript build filter function at runtime

While I go into my use-case in (hopefully not too much) detail below, keep in mind that the fundamental question is "How do I create a customized function at runtime in javascript?"
I have (potentially large) arrays of objects, and the user can build custom searches on those objects. The search function is passed an array of filters of the form
[{field:'name', predicate:'contains', modifier:'Joe'},
{field:'type', predicate:'is', modifier:'Boss'}]
which in this example would return all bosses named Joe.
Toward that end, I created a filtering function that applies the filters to the master list, which looks something like:
var matches = everythingOfThatType;
whereClause.forEach(function(filter) {
switch(filter.predicate) {
case '=':
case 'is':
matches = matches.filter(function(record) { return record[filter.field] == filter.modifier; });
console.log(filter, matches);
break;
case '!=':
case 'is not':
matches = matches.filter(function(record) { return record[filter.field] != filter.modifier; });
console.log(filter, matches);
break;
...
and so on.
It's working all right, but now I'm getting some gnarly complexity (special rules for filter combinations, recursive filtering on array properties, etc.), and for performance it would be better to only iterate through the list of all candidates once anyway.
my ideal solution would look something like
var filterFunc = magicallyCreateFilterFunc(filters);
var matches = everythingOfThatType.filter(filterFunc);
where magicallyCreateFilterFunc() would have something like the original switch statement, but instead of applying the filter, would add a line to the function that would eventually be applied to all the objects. Then I can add all the other complexity and recursion and whatnot in a tight, efficient manner.
It seems to me that JavaScript is well-suited for this sort of task (as an aside, the deeper I get into JavaScript the more I appreciate its depth), but I'm a little stuck on step 1: dynamically define a function based on data at run-time. I would really appreciate a nudge in the right direction.
It turns out there is a simple, clean way to do this. What I didn't know when I asked this question oh, so long ago is that closures and filters are best pals.
Rather than apply the filters in the switch statement, I can add the filter functions to an array, then use a closure to execute all the functions on each member of the array.
So my switch statement above looks more like
var buildFilterList = function(whereClause) {
var filterFunctions = [];
whereClause.forEach(function(filter) {
switch(filter.predicate) {
case '=':
case 'is':
filterFunctions.push((function(field) { return function(record) { return record[filter.field] == filter.modifier; })})(field));
break;
...
Which gives me a list of functions to apply to each element, each in a closure that contains the field it should be applied to. More complex filter functions could have more parameters. Now, how to efficiently take that list of filters and apply them? Closures again.
var filterApplicator = function(filters) {
return function(item) {
var passed = true, i = 0, filterCount = filters.length;
for (i = 0; passed && i < filterCount; i++) {
passed = filters[i](item);
}
return passed;
}
}
var filterFunctions = buildFilterList(whereClause);
matches = everythingOfThatType.filter(filterApplicator(filterFunctions));
filterApplicator() returns a function that will be applied to each element in the original array. That function is in a closure that includes the array of filter functions, so all it has to do is loop through those functions and apply them on the element until one fails.
(It should be noted that I have not tested this exact syntax, but the basic concept is what I wanted to pass on here.)

evaluating element class names of jquery array in a switch statement nested in for loop (javascript/jquery)

this is my first post ever on stackoverflow! I am a front-end web developer enthusiast and novice...If I am breaching the stackoverflow etiquette or rules of the road please let me know or give me the smack down..
I am trying to evaluate class names in an array of elements. If the class name contains a certain value then I want to manipulate an attribute for that element.
First, I create an array of elements using jquery stored as a variable:
note that buttons class naming convention is "share_button_[social media service name]"
Next, I create a for loop to iterate through the buttons variable
Within the for loop I have switch statement - the purpose is to evaluate each element in the Buttons array and add an href attribute to the element if it meets a certain criteria
Putting it all together:
var buttons = $('a[class^="share_button"]');
for (i=0; i < buttons.length; i++) {
switch (true) {
case ($(buttons[i]).attr('[class*="twitter"]')):
console.log('twitter!');
break;
case ($(buttons[i]).attr('[class*="linkedin"]')):
console.log('linkedin!');
break;
case ($(buttons[i]).attr('[class*="facebook"]')):
console.log('facebook_like!');
break;
case ($(buttons[i]).attr('[class*="google_plusone"]')):
console.log('google_plusone!');
break;
case ($(buttons[i]).attr('[class*="reddit"]')):
console.log('reddit!');
break;
}
}
This does not seem to be working at all. Here is the codepen, http://cdpn.io/fKoak
Is it a good practice to loop through a jquery array of elements like this?
Should I be using the switch statement in this case and am I using it correctly? (there are more possible cases then I have case statements for and I have no default - I want the cases without a match to "do noting")
In this particular case, what i wrong with the formation of my code that the desired outcome is not happening?
I think it would be better to do something more like this.
var $buttons = $('a[class^="share_button"]');
var $twitterButtons = $('[class*="twitter"]', $buttons);
$twitterButtons.each(function(i, button) {
//Do stuff to the twitter button
});
var $linkedinButtons = $('[class*="linkedin"]', $buttons);
$linkedinButtons.each(function(i, button) {
//Do stuff to the linkedin button
});
var $facebookButtons = $('[class*="facebook"]', $buttons);
$facebookButtons.each(function(i, button) {
//Do stuff to the facebook button
});
var $google_plusoneButtons = $('[class*="google_plusone"]', $buttons);
$google_plusoneButtons.each(function(i, button) {
//Do stuff to the google_plusone button
});
var $redditButtons = $('[class*="reddit"]', $buttons);
$redditButtons.each(function(i, button) {
//Do stuff to the reddit button
});
Adding the second parameter to your selectors gives them a context. So $('[class*="twitter"]', $buttons) looks through $buttons and selects those with a class containing twitter
You can use jQuery's each() method to iterate over the elements, then check the className
$('a[class^="share_button"]').each(function(i, elem) {
if ( elem.className.indexOf('twitter') != -1 ) {
console.log('twitter');
}else if ( elem.className.indexOf('linkedin') != -1 ) {
console.log('linkedin');
}else if (..... etc
});
A better approach would be to keep the switch, but google_plusone kinda screws that up with the underscore, so you'd have to replace that with something else:
$('a[class^="share_button"]').each(function(i, elem) {
switch( elem.className.split('_').pop() ) {
case 'twitter' :
console.log('twitter');
break;
case 'linkedin' :
console.log('linkedin');
break;
case 'googleplusone' :
// you'll have to remove the underscore or just check for "plusone"
}
});
I ultimately decided to drop the for loop and use jquery .each method -http://api.jquery.com/each/ - that was recommended by #adeno above. The two solutions offered by #adeno using .each both work good but I finally chose to go with the jquery .is method https://stackoverflow.com/a/2240085 - http://api.jquery.com/is/ - since we decided to use .each method it is already a "jquery solution" so using .is method to evaluate if the class name of each element contained a certain value was a lot less code - and allowed for more flexibility then the proposed .indexOf and .split/.pop methods by #adeno in imo..
#Tom also gave a workable solution. However, although I didn't mention it specifically in my question, I wanted a solution that would use an iterator to go through the array of selected button elements.
var $buttons = $('a[class^="share_button"]');
$buttons.each(function(i,e){
switch (true) {
case ($(e).is('[class*="twitter"]')):
alert('yea! it\'s a twitter button - now do something');
break;
case ($(e).is('[class*="linkedin"]')):
alert('yea! it\'s a linkedin button - now do something');
break;
case ($(e).is('[class*="facebook"]')):
alert('yea! it\'s a faceboook button - now do something');
break;
case ($(e).is('[class*="google_plusone"]')):
alert('yeah! it\'s a google plus one button - now do something');
break;
case ($(e).is('[class*="reddit"]')):
alert('yea! it\'s a reddit one button - now do something');
break;
}
});

Using an array through a switch() statement in Javascript

I'm trying to develop a simplified poker game through Javascript. I've listed all possible card combinations a given player might have in its hand ordered by its value, like this:
switch(sortedHand)
{
//Pair
case [1,1,4,3,2]: sortedHand.push(1,"Pair"); break;
case [1,1,5,3,2]: sortedHand.push(2,"Pair"); break;
case [1,1,5,4,2]: sortedHand.push(3,"Pair"); break;
case [1,1,5,4,3]: sortedHand.push(4,"Pair"); break;
case [1,1,6,3,2]: sortedHand.push(5,"Pair"); break;
case [1,1,6,4,2]: sortedHand.push(6,"Pair"); break;
case [1,1,6,4,3]: sortedHand.push(7,"Pair"); break;
case [1,1,6,5,2]: sortedHand.push(8,"Pair"); break;
case [1,1,6,5,3]: sortedHand.push(9,"Pair"); break;
case [1,1,6,5,4]: sortedHand.push(10,"Pair"); break;
Even though the "sortedHand" array stores values succesfully (as I've seen through console.log), the switch() statement always returns the default case, and everyone gets an straight flush. I fear this is a matter of the literal approach I've used to declare possible array values to be compared with the whole of "sortedHand", but I don't know any better. Is it even possible to use switch() in such a manner?
You can try switching on a textual representation of the array.
switch(sortedHand.join(' '))
{
//Pair
case '1 1 4 3 2': sortedHand.push(1,"Pair"); break;
case '1 1 5 3 2': sortedHand.push(2,"Pair"); break;
case '1 1 5 4 2': sortedHand.push(3,"Pair"); break;
case '1 1 5 4 3': sortedHand.push(4,"Pair"); break;
// etc.
}
As an alternative to specifying every case directly, perhaps build a function dispatch table using an object and get rid of the switch entirely.
var dispatch = {};
// Build the table however you'd like, for your application
for (var i = 0; i < 10; i++) {
(function(i) {
var hand = ...; // Add your hand logic here
dispatch[hand] = function() { sortedHand.push(i, "Pair"); };
})(i);
}
// Execute your routine
dispatch[sortedHand.join(' ')]();
the switch() statement always returns the default case
That's because the comparison doesn't check the array contents, but the array object itself. Objects are considered equal by their identity, so nothing will be equal to an object instantiated by a literal.
Is it even possible to use switch() in such a manner?
Yes, one can use objects in switch statements, but you would have to use references in the cases. Not applicable to your problem.
In your case, I'd suggest a stringification:
switch(sortedHand.join())
{
//Pair
case "1,1,4,3,2": sortedHand.push(1,"Pair"); break;
case "1,1,5,3,2": sortedHand.push(2,"Pair"); break;
case "1,1,5,4,2": sortedHand.push(3,"Pair"); break;
case "1,1,5,4,3": sortedHand.push(4,"Pair"); break;
case "1,1,6,3,2": sortedHand.push(5,"Pair"); break;
case "1,1,6,4,2": sortedHand.push(6,"Pair"); break;
case "1,1,6,4,3": sortedHand.push(7,"Pair"); break;
case "1,1,6,5,2": sortedHand.push(8,"Pair"); break;
case "1,1,6,5,3": sortedHand.push(9,"Pair"); break;
case "1,1,6,5,4": sortedHand.push(10,"Pair"); break;
but I guess there's an even better, arithmetic solution to detect the patterns you're after. That would be shorter and faster, but I'm not sure what exactly this snippet is supposed to do.
a faster, potentially reusable, and more flexible way of doing it is to use an object instead of case:
var ok= {
'1 1 4 3 2':1,
'1 1 5 3 2':2,
'1 1 5 4 2':3,
'1 1 5 4 3':4
}[ sortedHand.join(' ') ] ;
if(ok){ sortedHand.push( ok ,"Pair"); }
objects work great when one output is hinged on one input. if you need to do five things in each case, then you have to use case, but if you just need X to turn into Y, (a 1:1), Look Up Tables in the shape of Objects are ideal.
i imagine a RegExp can work here, i used them on a connect4 game to identify 4 in a row, but the above logic table should work as well or better than what you describe.
That will not quite work as you have it, but you can use sortedHand.join(',') and compare it with [1,1,1,2,5].join(',') which will compare the two arrays and should be true if their contents were the exact same (Be careful with numbers typed as strings!)
To be fair, though, I can't imagine why you would design your logic like that. Even a simple card game has hundreds of thousands of possible hands. You might do better using underscore.js's collection managing functions as it will be simpler, and just a better practice.
There are 1274 possible combinations of 5 cards in a regular deck. Listing them all out in a switch statement is completely ridiculous. Why not just have a function count any duplicates to check for 2,3,4-of-a-kinds and then check for straights? (Your array doesn't show suit so I'm assuming you are leaving it out).
But if you really want to do it that way, you could use a string. Strings work with switches, and you can even use them like arrays. e.g. "123"[0] == '1'. You can change them back and forth user functions like parseInt.
Since no one suggested this, use a for loop and count the number of cards with exactly the given value. Having such a function you can call 'cardCount = count(sortedHand, cardNumber)'. And of cause looping through all possible card-numbers will give you the hands.
Since a given player can only have 1x2, 2x2, 1x3, 1x3+1x2, 1x4 or straights/streets, you can return an array of all hits being arrays/objects stating the count and the cardNumber involved. So [{2, 5}, {3, 6}] for a full house.

Categories

Resources