I have a chunk of code that needs to determine if a given integer is between a set of other integers. I'd also like to have this in a case statement so as to not have a surplus of if..else statements everywhere. Here's a bit of the code:
switch (copies) {
case copies >= 0 && copies <= 99: copyPrice = 0.30; break;
case copies >= 100 && copies <= 499: copyPrice = 0.28; break;
case copies >= 500 && copies <= 749: copyPrice = 0.27; break;
case copies >= 750 && copies <= 1000: copyPrice = 0.26; break;
case copies > 1000: copies = 0.25; break;
}
where copies is an integer and copyPrice is a double. I get several errors saying that it expects to receive a integer but gets a boolean instead. What is the best (or optimal) way of setting this up? Any help is greatly appreciated!
This line (and similar):
case copies >= 0 && copies <= 99:
Returns a compiler error since it gives a boolean but the compiler expects an int since copy is declared as int.
One way to solve this is using an array with the desired ranks, and have a switch statement for the index found:
public double calculateCopyPrice(int copies) {
int[] range = { 99, 499, 749, 1000 };
double copyPrice = 0;
int index = -1;
for (int i = 0; i < range.length; i++) {
if (range[i] >= copies) {
index = i;
break;
}
}
switch (index) {
case 0: copyPrice = 0.30; break;
case 1: copyPrice = 0.28; break;
case 2: copyPrice = 0.27; break;
case 3: copyPrice = 0.26; break;
default: copyPrice = 0.25; break;
}
//probably more logic here...
return copyPrice;
}
After some tests, I've found a more flexible solution using a TreeMap<Integer, Double> which allows you to have a specie of range (what you're looking for) and ease the search by using TreeMap#ceilingEntry:
//TreeMap to store the "ranges"
TreeMap<Integer, Double> theMap = new TreeMap<Integer, Double>();
//add the data
theMap.put(99, 0.3);
theMap.put(499, 0.28);
theMap.put(749, 0.27);
theMap.put(1000, 0.26);
//the "default" value for max entries
theMap.put(Integer.MAX_VALUE, 0.25);
//testing the solution
Double ex1 = theMap.ceilingEntry(50).getValue();
Double ex2 = theMap.ceilingEntry(500).getValue();
Double ex3 = theMap.ceilingEntry(5000).getValue();
Double ex4 = theMap.ceilingEntry(100).getValue();
System.out.println(ex1);
System.out.println(ex2);
System.out.println(ex3);
System.out.println(ex4);
java has no native concept of "ranges", let alone support for them in case statements.
usually, when faced with this kind of logic i personally would do one of 2 things:
just have a chain of if-else statements. doesnt even habe to be a chain:
public static double calculateCopyPrice(int copies) {
if (copies > 1000) return 0.25;
if (copies >= 750) return 0.26;
//etc
}
this code has no "else" branches and is just as much typing as the switch syntax you'd like. possibly even less (i only check a single bound every time)
you could use an enum, say:
public enum Division {UNDER_100, 100_to_500, ... }
and then :
Division division = categorize(copies);
switch (division) {
case UNDER_100:
//etc
}
but this is serious overkill for what youre trying to do. i'd use that if this division is also useful elsewhere in your code.
Switch case function must have an exact number in case. For example:
case 0:
case 1:
You're trying to use case from some value to some value and it's not implemented that way in Java. For your problem, you must use if-else statement since it's impossible to do it with switch case. Hope it helped.
Look the problem is very basic..
In a switch statement it allows only the following datatypes and wrapper classes
Byte,short,char,int,Byte,Short,Character,Integer,enum,String..
If you are passing anything other than that will give you an error.
In your case the condition which you are evaluating will give you result which is a Boolean value.
NavigableMap.seilingEntry() may be a good solution in many cases,
but in other cases the following may be clearer:
double getPrice(int copies){
return copies>1000 ? 0.25
: copies>750 ? 0.26
: copies>500 ? 0.27
: copies>100 ? 0.28
: copies>0 ? 0.30
: 0; // or check this condition first, throwing an exception
}
Related
Good Evening,
I created this method for a class. I used a switch/case to execute depending on the value of expression. I included an if-else method for each case. I do get an error on case 1-> switch rules are a preview feature and are disabled by default. I attempted to add a : after case 1 and case 2but my results reached high numbers for the sets. I changed the : to -> and it worked appropriately. Now I am wondering if this was a proper way to set the case statements or should it be written differently.
private void playGame()
{
double winCheck = Math.random();
switch (matchServer) {
case 1 ->{
if (winCheck <= player1WinProb)
player1GamesWon++;
else
player2GamesWon++;
matchServer = 2;
}
case 2 ->{
if (winCheck <= player2WinProb)
player2GamesWon++;
else
player1GamesWon++;
matchServer = 1;
A correct switch statement must use ':'
Also, 'break' is missing. This to avoid executing next cases.
You can add 'default' that means that case 1 and case 2 were not presented.
switch (matchServer) {
case 1:
if (winCheck <= player1WinProb)
player1GamesWon++;
else
player2GamesWon++;
matchServer = 2;
break;
case 2:
if (winCheck <= player2WinProb)
player2GamesWon++;
else
player1GamesWon++;
matchServer = 1;
break;
default:
//If it was not 1 or 2
//Printing the values can help
}
I have different fields using the same parameters i.e. same grading scale. I want to use switch statement to return grades for different fields using the same scale. Something like this. I thought that there was something like this: switch (attend, job, initiative) { that would combine the three variables.
int attend = 5;
int job = 5;
int initiative = 5;
switch (attend) {
case 1:
getattendo = 5;
break;
case 2:
getattendo = 4;
break;
case 3:
getattendo = 3;
break;
case 4:
getattendo = 2;
case 5:
getattendo = 1;
break;
default:
getattendo = 0; // null
}
Your help is appreciated.
fmk
Enum works well with switch cases. So, you can define an enum that represents your range of value of it is a finite and reasonable range of values :
public enum OPTIONS {
OPTION1(5, 5, 5),
OPTION2(5, 2, 4),
OPTION3(1, 2, 3),
OPTION4(4, 4, 1);
private final int attend;
private final int jobs;
private final int initiative;
Directive(int attend, int jobs, int initiative) {
this.attend = attend;
this.jobs = jobs;
this.initiative = initiative;
}
// ... optional setters & getters
}
Given your create OPTION Enum, you can use a switch to handle the different cases :
switch (OPTION) {
case OPTION1:
getattendo = 5;
break;
case OPTION2:
getattendo = 4;
break;
case OPTION3:
getattendo = 3;
break;
case OPTION4:
getattendo = 2;
break;
default:
getattendo = 0; // null
break;
}
Note: Your switch is legitimate only if you have a finite number of condition. Otherwise, use a method to calculate your result.
A trick you use utilizes the unary or operation for checking binary digit presence.
This will help get you started on switching according to various conditions.
This is similar to how file permissions work in Linux.
public class ScoreCombinator {
public static final int ATTEND = 1; // binary: 001
public static final int JOB = 2; // binary: 010
public static final int INITIATIVE = 4; // binary: 100
public static void main(String[] args) {
evaluate(ATTEND | INITIATIVE); // Attend and Initiative
evaluate(INITIATIVE | ATTEND | JOB); // Attend, Job, and Initiative
}
private static void evaluate(int value) {
switch (value) {
case ATTEND: {
System.out.println("Attend");
break;
}
case ATTEND | JOB: {
System.out.println("Attend and Job");
break;
}
case ATTEND | JOB | INITIATIVE: {
System.out.println("Attend, Job, and Initiative");
break;
}
case ATTEND | INITIATIVE: {
System.out.println("Attend and Initiative");
break;
}
case JOB: {
System.out.println("Job");
break;
}
case JOB | INITIATIVE: {
System.out.println("Job and Initiative");
break;
}
case INITIATIVE: {
System.out.println("Initiative");
break;
}
}
}
}
Something like switch(a,b,c) is not possible.
If all values are the same, just use one of the valueslandmaybe verify that all values are the same).
However, there are workarounds if you want to switch-case with multiple numbers:
mathematical solution
For example, you could use prime numbers for this. As you only want to switch numbers, this is possible as long as there is a prime number higher than the highest expected value(for attend, prime and job).
Instead of switch(attend, job, initiative), you use switch((attend*prime+job)*prime+initiative) and instead of case (exampleAttend, exampleJob, exampleInitiative):, you use case ((exampleAttend*prime+exampleJob)*prime+exampleInitiative):
Note that prime must be the same in the switch and case statements.
Note that you should test if any of the input numbers is higher than the prime. This would logically lead to the default case but it could lead to collissions.
You may also want to make sure that the prime to the forth power is lower than the max value of the data type or there may be overflows.
On the other side, this method should be more performant than the second.
simple string concadation
Another option is to work with strings. As the string representation of a number is unique (to the number) and it does not contain some characters (like spaces), you can concadate those numbers and use such a character to seperate them.
Instead of switch(attend, job, initiative), you use switch(attend+" "+job+" "+initiative) and instead of case (exampleAttend,exampleJob,exampleInitiative):, you use case (exampleAttend+" "+exampleJob+" "+exampleInitiative):.
This is obviously easier and fail-safer than the first method involving prime numbers but there should be a performance impact as concadating strings is slower than multiplying ints.
Another possibility is to use enums. Look at the other answer by #Hassam Abdelillah
if you want to know how this works. If you like the enum approach, feel free to upvote the other answer.
Is there a way to grab the resulting number from each iteration of this loop and compare it to the next?
This is a Slot Machine Sim in Java,
I'm trying to find a way to see how many of the results match.
so I thought I would capture the number that is resulted from each round of the For loop and compare it to the previous one.
but I have no idea how to write that?
is there a better way to do this?
what I have so far:
for (int count=1; count<= 3 ; ++count)
{
number = slotM.nextInt(6);
switch (number)
{
case 0:
System.out.print("-cherries-");
break;
case 1:
System.out.print("-Oranges-");
break;
case 2:
System.out.print("-Palms-");
break;
case 3:
System.out.print("-Bells-");
break;
case 4:
System.out.print("-Melones-");
break;
default:
System.out.print("-Bars-");
break;
}
System.out.print(number);
}
Yep there are several better ways. If you have a fixed number of options (6 in your case) an enum might be a good option:
enum Picture {
CHERRIES, ORANGES, PALMS, BELLS, MELONS, BARS;
public String getName() {
return "-" + name().substring(0, 1) + name().substring(1).toLowerCase() + "-";
}
That way you can store your numbers as pictures rather than numbers.
Picture pictures[3];
Random random = new Random();
for (int i = 0; i < pictures.length; i++)
picture[i] = Picture.values[random.nextInt(pictures.length)];
To get the printed version:
for (Picture picture: picture)
System.out.print(picture.getName());
You’ll need some kind of storage outside of the loop so that each iteration can reference it.
int[] results Look in to arrays - you can put the results of each round into a part of the array, and look up the value.
You are declaring your count variable in the for loop, just declare outside and make a comparison with it
This question already has answers here:
switch expression can't be float, double or boolean
(6 answers)
Closed 5 years ago.
I used to check int values in case statements but is there any way check double values too? I can't use If else. This is an assignment. Thank you.
yes, but it won't perform very well. This will work
// don't do this, unless you want readability not performance.
switch(Double.toString(d)) {
case "1.0":
break;
case "Infinity":
break;
}
Instead you should use a series of if/else statements or use a Map<Double, DoubleConsumer> for a long list of doubles.
You can use a NavigableMap for efficient range searches.
NavigableMap<Double, DoubleConsumer> map = new TreeMap<>();
// default value is an assertion error
map.put(Double.NEGATIVE_INFINITY, d -> new AssertionError(d));
double upperBound = 12345;
map.put(upperBound, d -> new AssertionError(d));
// if >= 1.0 then println
map.put(1.0, System.out::println);
public static void select(NavigableMap<Double, DoubleConsumer> map, double d) {
Map.Entry<Double, DoubleConsumer> entry = map.floorEntry(d);
entry.getValue().accept(d);
}
Since double values provide an exact representation only in case when the value can be expressed as a sum of powers of 2 that located "close enough" to each other (within the length of mantissa), and because switch works only with exact matches, you cannot use doubles in a switch in a general case.
The basic reason for it is the same as the need to be careful when using == to compare doubles. The solution is the same as well: you should use a chain of if-then-else statements to find the desired value
if (a <= 0.2) {
...
} else if (a < 0.5) {
...
} else if (a < 0.9) {
...
} else {
...
}
or use a TreeMap<Double,Something> and perform a limit search:
TreeMap<Double,Integer> limits = new TreeMap<Double,Integer>();
limits.put(0.2, 1);
limits.put(0.5, 2);
limits.put(0.9, 3);
...
Map.Entry<Double,Integer> e = limits.ceilingEntry(a);
if (e != null) {
switch(e.getValue()) {
case 1: ... break;
case 2: ... break;
case 3: ... break;
}
}
Switch cases only take byte, short, char, and int. And a few other special cases.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
got thinking about having to repeatedly convert from int to String over the course of one of the apps I'm creating for Android. I sat down and wrote a little utility class that I think would alleviate the allocation of lurking variables that you cannot see because of function calls like Integer.toString(), and etc...
private int[] iMods = {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000};
private int tmpInt = 0;
private int MAX_DIGITS = 6;
private char[] cScoreDigit = new char[MAX_DIGITS];
private int[] iScoreDigit = new int[MAX_DIGITS];
private StringBuilder mScoreStringBuilder = new StringBuilder("000000");
public String intToString(final int pInt, final int pMAX_DIGITS){
MAX_DIGITS = pMAX_DIGITS;
for (tmpInt = 1; tmpInt <= MAX_DIGITS; tmpInt++){ // Set each cScoreDigit to proper equivalent of iScoreDigit without cast!
switch ((pInt % iMods[tmpInt]) / iMods[tmpInt - 1]){
case 0:
cScoreDigit[MAX_DIGITS - tmpInt] = '0';
break;
case 1:
cScoreDigit[MAX_DIGITS - tmpInt] = '1';
break;
case 2:
cScoreDigit[MAX_DIGITS - tmpInt] = '2';
break;
case 3:
cScoreDigit[MAX_DIGITS - tmpInt] = '3';
break;
case 4:
cScoreDigit[MAX_DIGITS - tmpInt] = '4';
break;
case 5:
cScoreDigit[MAX_DIGITS - tmpInt] = '5';
break;
case 6:
cScoreDigit[MAX_DIGITS - tmpInt] = '6';
break;
case 7:
cScoreDigit[MAX_DIGITS - tmpInt] = '7';
break;
case 8:
cScoreDigit[MAX_DIGITS - tmpInt] = '8';
break;
case 9:
cScoreDigit[MAX_DIGITS - tmpInt] = '9';
}
}
// Delete all 0's
mScoreStringBuilder.delete(0, mScoreStringBuilder.length());
return mScoreStringBuilder.append(cScoreDigit).toString();
}
Now I'm just curious as to A) whether this is actually the correct way to do something like this, and B) whether something like this is worth looking into because of the extra math taking place on each step? Seems counter productive, but would at least restrain the GC from running correct? Thanks in advance!
[EDIT]
It's been brought to my attention that the StringBuilder.toString() will actually allocate a temporary object, which is what I was trying to avoid. Any other way to simply convert from char[] to String without having an allocation? Or like stated below is this just not possible with String class?
No, the toString at the end creates a new String (Check the code if you like, java library sources are all available).
Since strings are immutable, there is really no way to avoid allocation because you return a string.
If you return the string builder you used to build your number in and reused it the next time you were called and NEVER converted it to a string you'd be fine, but the second you convert it to a string (no matter how you did it) you are allocating memory.
To do this your method would either have to accept a passed-in mutable object (StringBuilder or char array) or it would have to reuse a static one (making it single threaded)
I tried this once and it always comes down to converting it to a string at some point undoing all your work and making it even slower than it would have been if you'd just used the obvious way.
Also remember that in Java short-term memory allocations aren't as bad as you'd think--they are more like stack allocations in C in terms of performance.
The research and testing I did indicated that the one thing you can do is avoid concatenating strings in a loop--everything else (including one-time string concatenations) the simplest code will be just as fast or faster than anything you can come up with.