Could these "if statements" be simplified? - java

I have the following method:
public static String format_String(int hours, int minutes, int seconds)
{
if(hours > 0 && minutes > 0 && seconds > 0) return hours + " hours, " + minutes + " minutes and " + seconds + " seconds.";
else if(hours > 0 && minutes > 0 && seconds == 0) return hours + " hours and " + minutes + " minutes.";
else if(hours > 0 && minutes == 0 && seconds > 0) return hours + " hours and " + seconds + " seconds.";
else if(hours > 0 && minutes == 0 && seconds == 0) return hours + " hours.";
else if(hours == 0 && minutes > 0 && seconds > 0) return minutes + " minutes and " + seconds + " seconds.";
else if(hours == 0 && minutes > 0 && seconds == 0) return minutes + " minutes.";
else //if(hours == 0 && minutes == 0 && seconds > 0)
return seconds + " seconds.";
}
Can this method be simplified?

The tricky part is whether to separate parts with " and " or ",", which depends on how many non-zero parts appear to the right of the part you are currently printing. The rest (printing the names and numbers) is easy.
Hence you can reduce the number of branches by building the string from right-to-left.
public static String format_String(int hours, int minutes, int seconds)
{
StringBuilder result = new StringBuilder(".");
String sep = "", nextSep = " and ";
if (seconds > 0) {
result.insert(0, " seconds").insert(0, seconds);
sep = nextSep;
nextSep = ", ";
}
if (minutes > 0) {
result.insert(0, sep).insert(0, " minutes").insert(0, minutes);
sep = nextSep;
nextSep = ", ";
}
if (hours > 0) {
result.insert(0, sep).insert(0, " hours").insert(0, hours);
}
return result.toString();
}
or more generally:
public static String formatString(SortedMap<TimeUnit, Integer> parts) {
StringBuilder result = new StringBuilder(".");
String sep = "", nextSep = " and ";
for (Map.Entry<TimeUnit, Integer> e: parts.entrySet()) {
TimeUnit field = e.getKey();
Integer quantity = e.getValue();
if (quantity > 0) {
result.insert(0, sep)
.insert(0, field.toString().toLowerCase())
.insert(0, ' ')
.insert(0, quantity);
sep = nextSep;
nextSep = ", ";
}
}
return result.toString();
}

Think of how you would prepare to SAY the same sentence.
if hours > 0 then say the hours
if minutes > 0 then say the minutes
if seconds > 0 then say the seconds
Then create the logic using a StringBuilder with a single return at the end.

You could use the ternary operator to make it a little less verbose:
return
(hours > 0 && minutes > 0 && seconds > 0) ? hours + " hours, " + minutes + " minutes and " + seconds + " seconds." :
(hours > 0 && minutes > 0 && seconds == 0) ? hours + " hours and " + minutes + " minutes." :
(hours > 0 && minutes == 0 && seconds > 0) ? hours + " hours and " + seconds + " seconds." :
(hours > 0 && minutes == 0 && seconds == 0) ? hours + " hours." :
(hours == 0 && minutes > 0 && seconds > 0) ? minutes + " minutes and " + seconds + " seconds." :
(hours == 0 && minutes > 0 && seconds == 0) ? minutes + " minutes." :
seconds + " seconds.";

How about this?
public static String formatTime(int hours, int minutes, int seconds) {
List<String> parts = new ArrayList<String>(3);
if (hours > 0) parts.add(hours + " hours");
if (minutes > 0) parts.add(minutes + " minutes");
if (parts.isEmpty() || seconds > 0) parts.add(seconds + " seconds");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < parts.size(); i++) {
if (i > 0) builder.append((i < parts.size() - 1) ? ", " : " and " );
builder.append(parts.get(i));
}
return builder.append(".").toString();
}
It's more scalable. I only question if it's readable among new-to-Java developers.

Assuming all values will always be >= 0. The code looks more complicated, but there are MANY fewer comparisons!
if(hours > 0) {
if(minutes > 0) {
if(seconds > 0) return hours + " hours, " + minutes + " minutes and " + seconds + " seconds.";
return hours + " hours and " + minutes + " minutes.";
}
if(seconds > 0) return hours + " hours and " + seconds + " seconds.";
return hours + " hours.";
}
if(minutes > 0 ) {
if(seconds > 0 ) return minutes + " minutes and " + seconds + " seconds.";
return minutes + " minutes.";
}
return seconds + " seconds.";

Related

Weka Evaluation Arguments 0/1

May I know what is the argument need to sset in ()? 0 or 1? My datasets have three classes.
System.out.println("False Negative % = " + eval.falseNegativeRate(1));
System.out.println("True Negative % = " + eval.trueNegativeRate(1));
System.out.println("True Positive % = " + eval.truePositiveRate(1));
System.out.println("Accuracy % = " + accuracy);
System.out.println("Precision % = " + eval.precision(1));
System.out.println("Recall % = " + eval.recall(1));
System.out.println("F-Measure % = " + eval.fMeasure(1));
System.out.println("Error rate % = " + eval.errorRate());

How do I print the integer that is not 0?

Doing code for my java class, program runs as expected the only issue I'm having is if the interstate is, for example, 405 when it prints it prints 05 marking the question wrong because the question is just looking for 5 . Any help?
import java.util.Scanner;
highwayNumber = scnr.nextInt();
if ((highwayNumber > 999) || (highwayNumber < 1)) {
System.out.println(highwayNumber + " is not a valid interstate highway number.");
}
else if ((highwayNumber < 100) && (highwayNumber > 0) && (highwayNumber % 2 == 0)) {
System.out.println("The " + highwayNumber + " is primary, going east/west.");
}
else if ((highwayNumber < 100) && (highwayNumber > 0) && (highwayNumber % 2 != 0)) {
System.out.println("The " + highwayNumber + " is primary, going north/south.");
}
else if ((highwayNumber > 99) && (highwayNumber < 1000) && (highwayNumber % 2 == 0)) {
System.out.println("The " + highwayNumber + " is auxiliary, serving the " + String.valueOf(highwayNumber).substring(1) + ", going east/west.");
}
else if ((highwayNumber > 99) && (highwayNumber < 1000) && (highwayNumber % 2 != 0)) {
System.out.println("The " + highwayNumber + " is auxiliary, serving the " + String.valueOf(highwayNumber).substring(1) + ", going north/south.");
}
}
}
Just replace substring with % modulus operator:
System.out.println("The " + highwayNumber + " is auxiliary, serving the " + String.valueOf(highwayNumber % 100) + ", going east/west.");
System.out.println("The " + highwayNumber + " is auxiliary, serving the " + String.valueOf(highwayNumber % 100) + ", going north/south.");

While loop for change making

I am learning Java and am making code that converts pennies in to change. It is completed however, I am unsure what to enter for the while loop. I would have used while(!change.equals("END")) but this can't be done because change is an integer, so what can I do?
class Main {
public static void main(String args[]) {
System.out.print("#Please enter the amount of change : ");
int change = BIO.getInt();
if (change <= 500 && change >= 1) {
System.out.print("Amount" + "\t" + "Coins" + "\n");
}
while (change =) {
int twopounds, pounds, fifty, twenty, ten, five, two, one;
twopounds = change / 200;
int left = change % 200;
pounds = left / 100;
left = left % 100;
fifty = left / 50;
left = left % 50;
twenty = left / 20;
left = left % 20;
ten = left / 10;
left = left % 10;
five = left / 5;
left = left % 5;
two = left / 2;
left = left % 2;
one = left / 1;
int nbCoins = twopounds + pounds + fifty + twenty + ten + five + two + one;
if (change > 500 || change < 1) {
System.out.print("Invalid amount " + change + "p" + "\n");
}
if (change <= 500 && change >= 1) {
if (nbCoins == 1) {
System.out.print(change + "p " + "\t" + nbCoins + " coin ");
} else {
System.out.print(change + "p " + "\t" + nbCoins + " coins ");
}
if (twopounds > 0) {
System.out.print(twopounds > 1 ? twopounds + "*200p " : "200p ");
}
if (pounds > 0) {
System.out.print(pounds > 1 ? pounds + "*100p " : "100p ");
}
if (fifty > 0) {
System.out.print(fifty > 1 ? fifty + "*50p " : "50p ");
}
if (twenty > 0) {
System.out.print(twenty > 1 ? twenty + "*20p " : "20p ");
}
if (ten > 0) {
System.out.print(ten > 1 ? ten + "*10p " : "10p ");
}
if (five > 0) {
System.out.print(five > 1 ? five + "*5p " : "5p ");
}
if (two > 0) {
System.out.print(two > 1 ? two + "*2p " : "2p ");
}
if (one > 0) {
System.out.print(one > 1 ? one + "*1p " : "1p ");
}
System.out.print("\n");
}
System.out.print("#Please enter the amount of change : ");
change = BIO.getInt();
}
}
}
Thanks :)
It depends on what BIO is. Generally, there are options like .hasNextToken() if it is Enumerable. But, without knowing what that variable is declared as, I can't tell you what your trigger would be.
maybe this will work:
boolean flag = true;
while(flag){
//do things
if(condition_when_you_want_your_loop_to_stop){
flag = false;
}
}

Converting pennies in to change

I am learning Java and am making code that converts the number of pennies in to change when entered.
One thing I need to change is my output so that if there is only one coin it prints solely as 20p rather than 1*20p.
I would also appreciate if anyone notes any other improvements that could be made.
Thanks :)
class Main {
public static void main( String args[] ) {
System.out.print("#Please enter the amount of change : ");
int change = BIO.getInt();
while(change > 0)
{
int twopounds, pounds, fifty, twenty, ten, five, two, one;
twopounds = change / 200;
int left = change % 200;
pounds = left / 100;
left = left % 100;
fifty = left / 50;
left = left % 50;
twenty = left / 20;
left = left % 20;
ten = left / 10;
left = left % 10;
five = left / 5;
left = left % 5;
two = left / 2;
one = left / 1;
int nbCoins = twopounds + pounds + fifty + twenty + ten + five + two + one;
if (change == 1)
{
System.out.print("1 coin" + "\n");
}
if (change > 500)
{
System.out.print("Invalid amount " + change + "p" + "\n");
}
if (change <= 500 && change > 1)
System.out.print(change + "p " + nbCoins +" coins ");
{
if ( twopounds > 0 )
{
System.out.print( twopounds > 0 ? twopounds + "*200p " : "" );
}
if ( pounds > 0 )
{
System.out.print( pounds > 0 ? pounds + "*100p " : "" );
}
if ( fifty > 0 )
{
System.out.print( fifty > 0 ? fifty + "*50p " : "" );
}
if ( twenty > 0 )
{
System.out.print( twenty > 0 ? twenty + "*20p " : "" );
}
if ( ten > 0 )
{
System.out.print( ten > 0 ? ten + "*10p " : "" );
}
if ( five > 0 )
{
System.out.print( five > 0 ? five + "*5p " : "" );
}
if ( two > 0 )
{
System.out.print( two > 0 ? two + "*2p " : "" );
}
if ( one > 0 )
{
System.out.print( one > 0 ? one + "*1p " : "" );
}
System.out.print("\n");
}
System.out.print("#Please enter the amount of change : ");
change = BIO.getInt();
}
}
}
what you could do is define your coins as emums,
ie:
enum Coin {
twopounds(200), pounds(100), fifty(50), twenty(20), ten(10), five(5), two(
2), one(1);
int value;
Coin(int value) {
this.value = value;
}
int getCoins(int amount){
return amount/value;
}
int getReminder(int amount){
return amount%value;
}
}
then you could do
int change = 321;
for (Coin coin : Coin.values()){
int count = coin.getCoins(change );
if (count!=0){
System.out.println(coin.name()+" : " +count);
}
change = coin.getReminder(change );
}
and that will prints you your change in coins,
you could take this further, and define your wallet where you hold all your money
ie
class Wallet{
int money;
int getAllCoins(Coin coin){
int coins = coin.getCoins(money);
money=coin.getReminder(money);
return coins;
}
}
but this will be overkill for this simple scenario
You don't want entries with 1 coin to be displayed as 1*value so replace the comparison
System.out.print( twopounds > 0 ? twopounds + "*200p " : " " );
to
System.out.print( twopounds > 1 ? twopounds + "*200p " : "200p " );
in other words, you compare the numberOfCoins to one, if it's just one coin, then write just the value of the coin. Else write numberOfCoins * value
Replace the relevant part of your code with this:
if ( twopounds > 0 )
{
System.out.print( twopounds > 1 ? twopounds + "*200p " : "200p " );
}
if ( pounds > 0 )
{
System.out.print( pounds > 1 ? pounds + "*100p " : "100p " );
}
if ( fifty > 0 )
{
System.out.print( fifty > 1 ? fifty + "*50p " : "50p " );
}
if ( twenty > 0 )
{
System.out.print( twenty > 1 ? twenty + "*20p " : "20p " );
}
if ( ten > 0 )
{
System.out.print( ten > 1 ? ten + "*10p " : "10p " );
}
if ( five > 0 )
{
System.out.print( five > 1 ? five + "*5p " : "5p " );
}
if ( two > 0 )
{
System.out.print( two > 1 ? two + "*2p " : "2p " );
}
if ( one > 0 )
{
System.out.print( one > 1 ? one + "*1p " : "1p " );
}

Removing decimals from dividing

In a recent game I'm developing, I've made shops.
When you buy an item and try to sell it, the selling price drops to 75% of what the buying price is.
After buying an item for 154 gold pieces, It says the shop will buy for 115.5 gold pieces, but you get 115 gold pieces from selling.
I wish to remove the ".5" from "115.5"
Any help is appreciated.
int ShopValue = (int)Math.floor(getItemShopValue(removeId, 1, removeSlot));
String ShopAdd = "";
if (ShopValue >= 1000 && ShopValue < 1000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000) + "k)";
} else if (ShopValue >= 100) {
ShopAdd = " (" + (ShopValue*.75 / 1) + " coins)";
} else if (ShopValue >= 1000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000) + " million)";
} else if (ShopValue >= 1000000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000000) + " billion)";
}
c.sM(c.getItems().getItemName(removeId)+": shop will buy for <col=255>"+ShopAdd+"</col> coins");
}
}
I would just use Math.floor.
int ShopValue = (int)Math.floor(getItemShopValue(removeId, 1, removeSlot));
String ShopAdd = "";
if (ShopValue >= 1000 && ShopValue < 1000000) {
ShopAdd = " (" + Math.floor(ShopValue*.75 / 1000) + "k)";
} else if (ShopValue >= 100) {
ShopAdd = " (" + Math.floor(ShopValue*.75 / 1) + " coins)";
} else if (ShopValue >= 1000000) {
ShopAdd = " (" + Math.floor(ShopValue*.75 / 1000000) + " million)";
} else if (ShopValue >= 1000000000) {
ShopAdd = " (" + Math.floor(ShopValue*.75 / 1000000000) + " billion)";
}
c.sM(c.getItems().getItemName(removeId)+": shop will buy for <col=255>"+ShopAdd+"</col> coins");
}
}
If you wanted to be a little more generous to your players you might use Math.ceil instead ;-)
You can get what you want by either:
Decalring ShopAdd as an integer. This might cause other problems if you're (going to be) using ShopAdd somewhere else that needs it to be a floating point data type though.
Casting ShopAdd into an int right before it's printed. This is a quick fix, and isn't that great if you plan to print ShopAdd in many places, because they'll all have to be casted.
Some example java code:
public class PrintingNumbers {
public static void main(String[] args) {
int i = 1;
double d = 1;
System.out.println("printing integer: " + i);
System.out.println("printing double: " + d + " (not what you want)");
System.out.println("printing casted double: " + (int) d);
}
}
Output of above java code:
printing integer: 1
printing double: 1.0 (not what you want)
printing casted double: 1
In your case, option 1 would look something like this:
int ShopAdd // declare ShopAdd as an integer
...
int ShopValue = (int)Math.floor(getItemShopValue(removeId, 1, removeSlot));
String ShopAdd = "";
if (ShopValue >= 1000000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000000) + " billion)";
} else if (ShopValue >= 1000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000) + " million)";
} else if (ShopValue >= 1000) {
ShopAdd = " (" + (ShopValue*.75 / 1000) + "k)";
} else if (ShopValue >= 100) {
ShopAdd = " (" + (ShopValue*.75 / 1) + " coins)";
}
c.sM(c.getItems().getItemName(removeId)+": shop will buy for <col=255>"+ShopAdd+"</col> coins");
}
}
And, option 2 would look like this:
int ShopValue = (int)Math.floor(getItemShopValue(removeId, 1, removeSlot));
String ShopAdd = "";
if (ShopValue >= 1000000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000000) + " billion)";
} else if (ShopValue >= 1000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000) + " million)";
} else if (ShopValue >= 1000) {
ShopAdd = " (" + (ShopValue*.75 / 1000) + "k)";
} else if (ShopValue >= 100) {
ShopAdd = " (" + (ShopValue*.75 / 1) + " coins)";
}
// casting ShopAdd into an int when printing
c.sM(c.getItems().getItemName(removeId)+": shop will buy for <col=255>"+(int)ShopAdd+"</col> coins");
}
}
I hope this helps! :)
As Kayaman already wrote in his comment, I would just cast it to an int or to an long - This will cut of the decimals without rounding.
If you want an integer as a result, the simple solution is to use integer maths.
long ShopValue = (long) (getItemShopValue(removeId, 1, removeSlot))*3/4;
String ShopAdd = " (";
if (ShopValue >= 750000000) {
ShopAdd = ShopValue / 750000000 + " billion";
} else if (ShopValue >= 1000000) {
ShopAdd = ShopValue / 750000 + " million";
} else if (ShopValue >= 1000) {
ShopAdd = ShopValue / 750 + "k";
} else {
ShopAdd = ShopValue + " coins";
}
ShopAdd += ")";
Note: your current implementation will print 800 as 0k
You can use Math.floor() as others said.
Apart from that: you may have a bug in your code logic. The 3rd and the 4th branches of the if statement are unreachable as the 2nd if clause covers them
if (ShopValue >= 100)
The correct way is to arrange them such that comparisons with greater numbers comes before comparisons with smaller numbers:
int ShopValue = (int)Math.floor(getItemShopValue(removeId, 1, removeSlot));
String ShopAdd = "";
if (ShopValue >= 1000000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000000) + " billion)";
} else if (ShopValue >= 1000000) {
ShopAdd = " (" + (ShopValue*.75 / 1000000) + " million)";
} else if (ShopValue >= 1000) {
ShopAdd = " (" + (ShopValue*.75 / 1000) + "k)";
} else if (ShopValue >= 100) {
ShopAdd = " (" + (ShopValue*.75 / 1) + " coins)";
}
c.sM(c.getItems().getItemName(removeId)+": shop will buy for <col=255>"+ShopAdd+"</col> coins");
}
}

Categories