How to convert 2k,1m,1g etc to 2000, 1000000 etc - java

Hello I'm new to java can anyone help me?
This code convert
2000 to 2k and 1000000 1m etc
private static final NavigableMap<Long, String> suffixes = new TreeMap<>();
static {
suffixes.put(1_000L, "k");
suffixes.put(1_000_000L, "M");
suffixes.put(1_000_000_000L, "G");
suffixes.put(1_000_000_000_000L, "T");
suffixes.put(1_000_000_000_000_000L, "P");
suffixes.put(1_000_000_000_000_000_000L, "E");
}
public String format(long value) {
//Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
if (value < 0) return "-" + format(-value);
if (value < 1000) return Long.toString(value); //deal with easy case
Map.Entry<Long, String> e = suffixes.floorEntry(value);
Long divideBy = e.getKey();
String suffix = e.getValue();
long truncated = value / (divideBy / 10); //the number part of the output times 10
boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
}
I need a code which reverse the conversion for example
2k to 2000 and 1m to 1000000

I got the solution just by storing the values in an ArrayList before converting and it worked osum. Thanks for the help everyone :)

I have posted a solution. Need proper input as proper validations are not included. Let me know if it fits your need. also you can add/modify the switch cases according to your need.
public class Test {
public static void main(String[] args) {
String values[] = {
"27",
"999",
"1.0 k",
"110.6 k",
"29.0 G",
"5m",
"5m30",
"2.7k",
"2k7",
"2k17",
"9.2 E",
"9.2EE"
};
Test test = new Test();
test.printValues(values);
}
private void printValues(String[] values) {
for (String value : values) {
if (isProperNumber(value)) {
printValue(value);
} else {
System.out.println("Not a proper number");
}
System.out.println("===================");
}
}
private void printValue(String value) {
String lastAlphabet = value.replaceAll("[^a-zA-Z]*$", "")
.replaceAll(".(?!$)", "");
long multiplier = 1L;
switch (lastAlphabet.toLowerCase()) {
case "k":
multiplier = 1_000L;
break;
case "m":
multiplier = 1_000_000L;
break;
case "g":
multiplier = 1_000_000_000L;
break;
case "t":
multiplier = 1_000_000_000_000L;
break;
case "p":
multiplier = 1_000_000_000_000_000L;
break;
case "e":
multiplier = 1_000_000_000_000_000_000L;
break;
default:
break;
}
String[] values = value.split(lastAlphabet);
if (multiplier == 1) {
System.out.println("" + values[0]);
} else {
double valueMultiplier = Double.parseDouble(values[0]);
double valueAdder;
try {
valueAdder = Double.parseDouble(values[1]);
} catch (ArrayIndexOutOfBoundsException ex) {
valueAdder = 0.0d;
}
double total = (valueMultiplier * multiplier) + valueAdder;
System.out.printf("%.0f\n", total);
}
}
private boolean isProperNumber(String value) {
value = value.replaceAll("\\s+", "");
String count = value.replaceAll("[.0-9]+", "");
return count.length() < 2;
}
}

no need to worry, just use simple JS Trick with Round figure up to 2 decimal places.
function somefunction(count){
if (count >= 1000) {
return Math.round((count/1000) * 10)/10+'k';
} else {
return count;
}
}
if you want put more functionalities, just put more else if with devide 1000 with more million or billion, just 2 or 3 more else if makes your code better.

private static final String dp(String value) {
if (value.contains("k") || value.contains("K")){
value.replace("k", "000");
value.replace("K", "000");
} else if (value.contains("m") || value.contains("M")){
value.replace("m", "000000");
value.replace("M", "000000");
} else if (value.contains("g") || value.contains("G")){
value.replace("g", "000000000");
value.replace("G", "000000000");
} ......
return value;
}

Related

integer to word conversion in java using map continue question

This is a probable answer of my question in stack overflow.Integer to word conversion
At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is
First: Huge numbers of variable use
2nd: Redundant code block as per program requirement
3rd: Multiple if else statement
I am thinking about this problems
Solution for 2nd problem: using user define function or macros to eliminate redundant code block
Solution for 3rd problem: Using switch case
My code:
public class IntegerEnglish {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
System.out.println("Enter the integer");
int input_number=in.nextInt();
Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
Map<Integer,String> number_place = new HashMap<Integer,String>();
Map<Integer,String> number_2nd = new HashMap<Integer,String>();
numbers_converter.put(0,"Zero");
numbers_converter.put(1,"One");
numbers_converter.put(2,"Two");
numbers_converter.put(3,"Three");
numbers_converter.put(4,"Four");
numbers_converter.put(5,"Five");
numbers_converter.put(6,"Six");
numbers_converter.put(7,"Seven");
numbers_converter.put(8,"Eight");
numbers_converter.put(9,"Nine");
numbers_converter.put(10,"Ten");
numbers_converter.put(11,"Eleven");
numbers_converter.put(12,"Twelve");
numbers_converter.put(13,"Thirteen");
numbers_converter.put(14,"Fourteen ");
numbers_converter.put(15,"Fifteen");
numbers_converter.put(16,"Sixteen");
numbers_converter.put(17,"Seventeen");
numbers_converter.put(18,"Eighteen");
numbers_converter.put(19,"Nineteen");
number_place.put(3,"Hundred");
number_place.put(4,"Thousand");
number_place.put(7,"Million");
number_place.put(11,"Billion");
number_2nd.put(2,"Twenty");
number_2nd.put(3,"Thirty");
number_2nd.put(4,"Forty");
number_2nd.put(5,"Fifty");
number_2nd.put(6,"Sixty");
number_2nd.put(7,"Seventy");
number_2nd.put(8,"Eighty");
number_2nd.put(9,"Ninty");
if(input_number== 0){
System.out.println("zero");
}
else if(input_number>0 && input_number<19){
System.out.println(numbers_converter.get(input_number));
}
else if(input_number>19 && input_number<100){
int rem=input_number%10;
input_number=input_number/10;
System.out.print(number_2nd.get(input_number));
System.out.print(numbers_converter.get(rem));
}
else if(input_number==100){
System.out.println(number_place.get(3));
}
else if(input_number>100 && input_number<1000){
int reminder=input_number%100;
int r1=reminder%10;
int q1=reminder/10;
int quot=input_number/100;
System.out.print(numbers_converter.get(quot) + "hundred");
if(reminder>0 && reminder<20){
System.out.print(numbers_converter.get(reminder));
}
else{
System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
}
}
else if(input_number==1000){
System.out.println(number_place.get(4));
}
else if(input_number>1000 && input_number<10000){
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
if(rem >0 && rem<20){
System.out.print(numbers_converter.get(rem));
}
else if(rem >19 && rem <100){
System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
}
}
else if(input_number>10000 && input_number<1000000000){
//Say number 418,229,356
int third_part=input_number%1000;//hold 356
input_number=input_number/1000;//hold 418,229
int sec_part=input_number%1000;//hold 229
input_number=input_number/1000;// hold 418
int rem_m=third_part%100;//hold 56
int rem_m1=rem_m%10;//hold 6
int rem_q=rem_m/10;// hold 5
int q_m=third_part/100;// hold 3
int sec_part_rem=sec_part%100;// hold 29
int sec_part_rem1=sec_part_rem%10;//9
int sec_part_q=sec_part_rem/10;//hold 2
int sec_q=sec_part/100;// hold 2
int input_q=input_number/100;// hold 4
int input_rem=input_number%100;//hold 18
int input_q_q=input_rem/10;//hold 1
int input_rem1=input_rem%10;// hold 8
System.out.print(numbers_converter.get(input_q) + " hundred ");
if(input_rem>0 && input_rem<20){
System.out.print(numbers_converter.get(input_rem)+ " Million ");
}
else{
System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
}
System.out.print(numbers_converter.get(sec_q) + " hundred ");
if(sec_part_rem >0 && sec_part_rem<20){
System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
}
else{
System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
}
System.out.print(numbers_converter.get(q_m) + " hundred ");
if(rem_m>0 && rem_m<20){
System.out.print(numbers_converter.get(rem_m));
}
else{
System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
}
}
}
}
Redundant Code Blocks
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.
How could I include user define function and switch case to minimize the code block.
Instead of storing the results in variables, use a method call:
int remainder100(int aNumber) {
return aNumber % 100;
}
int remainder10(int aNumber) {
return aNumber % 10;
}
...etc.
System.out.println(numbers_converter.get(remainder100(input_number)));
About 3rd problem: I wouldn't use switch ... case, too many cases.
Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).
To do that, use a loop like this:
ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
partialResult.add(convertThreeDigits(kiloCounter % 1000));
}
Then you can print out the contents of partialResult in reverse order to get the final number.
I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.
You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.
Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.
An example of a test would be
#Test
public void Convert102356Test() {
assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}
And here's the NumberToString class :
import java.util.HashMap;
import java.util.Map;
public class NumberToString {
// billion is enough for an int, obviously need more for long
private static String[] power3 = new String[] {"", "thousand", "million", "billion"};
private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
private static Map<String,String> number_tens = new HashMap<String,String>();
static {
numbers_below_twenty.put("0","");
numbers_below_twenty.put("1","one");
numbers_below_twenty.put("2","two");
numbers_below_twenty.put("3","three");
numbers_below_twenty.put("4","four");
numbers_below_twenty.put("5","five");
numbers_below_twenty.put("6","six");
numbers_below_twenty.put("7","seven");
numbers_below_twenty.put("8","eight");
numbers_below_twenty.put("9","nine");
numbers_below_twenty.put("10","ten");
numbers_below_twenty.put("11","eleven");
numbers_below_twenty.put("12","twelve");
numbers_below_twenty.put("13","thirteen");
numbers_below_twenty.put("14","fourteen ");
numbers_below_twenty.put("15","fifteen");
numbers_below_twenty.put("16","sixteen");
numbers_below_twenty.put("17","seventeen");
numbers_below_twenty.put("18","eighteen");
numbers_below_twenty.put("19","nineteen");
number_tens.put(null,"");
number_tens.put("","");
number_tens.put("0","");
number_tens.put("2","twenty");
number_tens.put("3","thirty");
number_tens.put("4","forty");
number_tens.put("5","fifty");
number_tens.put("6","sixty");
number_tens.put("7","seventy");
number_tens.put("8","eighty");
number_tens.put("9","ninty");
}
public static String convert(int value) {
if (value == 0) {
return "zero";
}
PoppableNumber number = new PoppableNumber(value);
String result = "";
int power3Count = 0;
while (number.hasMore()) {
String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
nextPart = join(nextPart, " ", power3[power3Count++], true);
result = join(nextPart, " ", result);
}
if (number.isNegative()) {
result = join("minus", " ", result);
}
return result;
}
public static String convertUnitTenHundred(String units, String tens, String hundreds) {
String tens_and_units_part = "";
if (numbers_below_twenty.containsKey(tens+units)) {
tens_and_units_part = numbers_below_twenty.get(tens+units);
}
else {
tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
}
String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
return join(hundred_part, " and ", tens_and_units_part);
}
public static String join(String part1, String sep, String part2) {
return join(part1, sep, part2, false);
}
public static String join(String part1, String sep, String part2, boolean part1Required) {
if (part1 == null || part1.length() == 0) {
return (part1Required) ? "" : part2;
}
if (part2.length() == 0) {
return part1;
}
return part1 + sep + part2;
}
/**
*
* Convert an int to a string, and allow the last character to be taken off the string using pop() method.
*
* e.g.
* 1432
* Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
*
* If there is nothing left, pop() will just return an empty string.
*
*/
static class PoppableNumber {
private int original;
private String number;
private int start;
private int next;
PoppableNumber(int value) {
this.original = value;
this.number = String.valueOf(value);
this.next = number.length();
this.start = (value < 0) ? 1 : 0; // allow for minus sign.
}
boolean isNegative() {
return (original < 0);
}
boolean hasMore() {
return (next > start);
}
String pop() {
return hasMore() ? number.substring(--next, next+1) : "";
}
}
}

Which data structure is good for equation solving

I planned to develop an equation solver from basic and able to do basic mathematics operations using below code. I have used a token stack structure which will used to store the deliminator and number token. Though this implementation is too basic, I want to improve it on later version. I just need some helps the way I use the data structure to store the token as a set of stacks. Please kindly suggest any mistake ?
import java.util.ArrayList;
import java.util.Stack;
class TokenStack<N, D> {
private Stack<N> numberStack;
private Stack<D> delimStack;
public TokenStack() {
numberStack = new Stack<N>();
delimStack = new Stack<D>();
}
public void pushN(N num) {
numberStack.push(num);
}
public N popN() {
return numberStack.pop();
}
public void pushD(D delim) {
delimStack.push(delim);
}
public D popD() {
return delimStack.pop();
}
public boolean isEmptyN() {
return numberStack.isEmpty();
}
public boolean isEmptyD() {
return delimStack.isEmpty();
}
}
public class GeneralST {
private static final char SPACE_DELIM = ' ';
private static final char ADD_DELIM = '+';
private static final char SUB_DELIM = '-';
private static final char MUL_DELIM = '*';
private static final char DIV_DELIM = '/';
protected static final char EQU_DELIM = '=';
private TokenStack<String, Character> tokens = new TokenStack<String, Character>();
protected ArrayList<Character> acceptedDelims = new ArrayList<Character>();
protected ArrayList<Character> mathsDelims = new ArrayList<Character>();
protected double result;
public double getResult() {
return result;
}
protected void setupDelims() {
acceptedDelims.add(SPACE_DELIM);
mathsDelims.add(ADD_DELIM);
mathsDelims.add(SUB_DELIM);
mathsDelims.add(MUL_DELIM);
mathsDelims.add(DIV_DELIM);
acceptedDelims.addAll(mathsDelims);
}
private void tokenize(String str) {
String reverse = "";
for (int i = str.length() - 1; i >= 0; i--) {
char charAt = str.charAt(i);
if (i > 1) {
char charPre = str.charAt(i - 1);
if (acceptedDelims.indexOf(charAt) == -1 && (charPre == '-' || charPre == '+')) {
reverse = reverse + charPre + charAt;
i--;
} else {
reverse = reverse + charAt;
}
} else {
reverse = reverse + charAt;
}
}
int i = 0;
while (reverse.length() > 2) {
char charAt = reverse.charAt(i);
char chartNext = reverse.charAt(i + 1);
if (acceptedDelims.indexOf(charAt) != -1 && acceptedDelims.indexOf(chartNext) != -1) {
String previous = reverse.substring(0, i);
if (!previous.equals("") && !previous.equals(" ")) {
tokens.pushN(previous);
}
if (mathsDelims.indexOf(charAt) != -1) {
tokens.pushD(charAt);
}
reverse = reverse.substring(i + 1);
i = i - previous.length() - 1;
}
i++;
}
if (!reverse.equals("")) {
tokens.pushN(reverse);
}
}
private double equate() {
double val = 0;
int step = 1;
int side = 1;
while (!tokens.isEmptyN() && !tokens.isEmptyD()) {
char delim = tokens.popD();
double val1 = Double.valueOf(tokens.popN());
double val2 = side * Double.valueOf(tokens.popN());
switch (delim) {
case ADD_DELIM:
val = val1 + val2;
break;
case SUB_DELIM:
val = val1 - val2;
break;
case MUL_DELIM:
val = val1 * val2;
break;
case DIV_DELIM:
try {
val = val1 / val2;
break;
} catch (Exception exception) {
exception.printStackTrace();
break;
}
case EQU_DELIM:
val = val1 - val2;
side = -1;
delim = '-';
}
String outString = "Step %d : %s %c %s = %f";
String printString = String.format(outString, step, val1, delim, val2, val);
step++;
System.out.println(printString);
tokens.pushN(String.valueOf(val));
}
return val;
}
public GeneralST(String str) {
System.out.println("--------------------------------------");
System.out.println("[EXP] : " + str);
setupDelims();
tokenize(str);
result = equate();
System.out.println("--------------------------------------");
}
public void PrintResult() {
System.out.println("Result = " + result);
}
}
class EquateST extends GeneralST {
public EquateST(String str) {
super(str);
}
#Override
protected void setupDelims() {
mathsDelims.add(EQU_DELIM);
super.setupDelims();
}
public void PrintResult() {
if (result == 0) {
System.out.println("Result = True");
} else {
System.out.println("Result = False");
}
}
}
class Main {
public static void main(String[] args) {
String[] equations = {"6 + 2 + -4 * 4 - 5", "6 + 2 - 4 * 4 = -5", "6 + -2 - 4 = 4 - 5"};
calculate(equations);
}
private static void calculate(String... equations)
{
for (String equation : equations) {
if (equation.contains("=")) {
EquateST equateST = new EquateST(equation);
equateST.PrintResult();
} else {
GeneralST generalST = new GeneralST(equation);
generalST.PrintResult();
}
}
}
}
Sample Results
--------------------------------------
[EXP] : 6 + 2 + -4 * 4 - 5
Step 1 : 6.0 + 2.0 = 8.000000
Step 2 : 8.0 + -4.0 = 4.000000
Step 3 : 4.0 * 4.0 = 16.000000
Step 4 : 16.0 - 5.0 = 11.000000
--------------------------------------
Result = 11.0
--------------------------------------
[EXP] : 6 + 2 - 4 * 4 = -5
Step 1 : 6.0 + 2.0 = 8.000000
Step 2 : 8.0 - 4.0 = 4.000000
Step 3 : 4.0 * 4.0 = 16.000000
Step 4 : 16.0 - -5.0 = 21.000000
--------------------------------------
Result = False
--------------------------------------
[EXP] : 6 + -2 - 4 = 4 - 5
Step 1 : 6.0 + -2.0 = 4.000000
Step 2 : 4.0 - 4.0 = 0.000000
Step 3 : 0.0 - 4.0 = -4.000000
Step 4 : -4.0 - -5.0 = 1.000000
--------------------------------------
Result = False
Your problem is "arithmetic evaluation".
It was mentioned in many book "Algorithm".
Best and simple way to solve it : using stack and "postfix notation".
You can find a lot of article with your favorite programming languages.

What I want to do is convert the double value of variable to exponential form only if number has more than 5 zero's after decimal point in java

This is my function to convert input values ->
private void frequencyUnitConverter(Utils.FrequencyUnit from, Utils.FrequencyUnit to, double input) {
double constant = 1;
switch (from) {
case HERTZ:
if (to == Utils.FrequencyUnit.KILOHERTZ) {
constant = 0.001;
} else if (to == Utils.FrequencyUnit.MEGAHERTZ) {
constant = 1e-6;
} else if (to == Utils.FrequencyUnit.GIGAHERTZ) {
constant = 1e-9;
}
break;
case KILOHERTZ:
if (to == Utils.FrequencyUnit.HERTZ) {
constant = 1000;
} else if (to == Utils.FrequencyUnit.MEGAHERTZ) {
constant = 0.001;
} else if (to == Utils.FrequencyUnit.GIGAHERTZ) {
constant = 1e-6;
}
break;
case MEGAHERTZ:
if (to == Utils.FrequencyUnit.HERTZ) {
constant = 1e+6;
} else if (to == Utils.FrequencyUnit.KILOHERTZ) {
constant = 1000;
} else if (to == Utils.FrequencyUnit.GIGAHERTZ) {
constant = 0.001;
}
break;
case GIGAHERTZ:
if (to == Utils.FrequencyUnit.HERTZ) {
constant = 1e+9;
} else if (to == Utils.FrequencyUnit.KILOHERTZ) {
constant = 1e+6;
} else if (to == Utils.FrequencyUnit.MEGAHERTZ) {
constant = 1000;
}
break;
}
double result = input * constant;
binding.outputNumText.setText(String.valueOf(result).toLowerCase());
}
Currently I get something like this ->
Here result should be 0.000123 format instead of 1.2299999999999998e-4 format.
After calculating result with double result = input * constant; How can I convert it to exponential format only and only if it has 5 zero's after decimal point otherwise print result in simple decimal format. e.g. 0.000123
It is not going to convert this number but to display this number you can do below,
double noExpo = 1.2299999999999998e-4;
NumberFormat formatter = new DecimalFormat("#0.000000");
Log.e("number", ":::" + formatter.format(noExpo));
output -->
number: 0.000123

Create with recursion basic mathematical operations with predefined definitions

I plan in JavaFX a new Game 'Number-Shape-System'. Basically its a little memory game where pictures are associated with numbers. So '2'='Swan', '5'='Hand(Fingers)' and so on. So the player see the exercise 'Swan + Fingers = ?'.
What I want is all possible mathematically operations following rules:
/*
* Generate all possible mathematical operations to the console with the numbers
* 0-12, where every result is (>= 0 && <= 12).
* - Mathematical operations are '+', '-', '*' and '/'.
* - The rule 'dot before line' shouldn't be used, instead the operations will
* be executed from left to right.
* - Every among result must be between (>= 0 && <= 12) and a whole number.
* - Only different numbers are allowed for the operations (an operation have
* 2 numbers). For example 2+3 is allowed, 3*3 not.
*
* A solution with recursive methods would be preferred. I want the output for
* the length 2-10.
*
* Example output with different length:
* - Length 3: 2+3(=5)*2(=10)
* - Length 5: 2+3(=5)*2(=10)+2(=12)/4(=3)
*/
I have prepared a example implementation, but I don't know how to convert it to a recursive functionality.
import java.util.ArrayList;
import java.util.List;
public class Generator {
private static final List<Double> numbers = new ArrayList<>();
private static final List<String> operations = new ArrayList<>();
static {
numbers.add(0.0);
numbers.add(1.0);
numbers.add(2.0);
numbers.add(3.0);
numbers.add(4.0);
numbers.add(5.0);
numbers.add(6.0);
numbers.add(7.0);
numbers.add(8.0);
numbers.add(9.0);
numbers.add(10.0);
numbers.add(11.0);
numbers.add(12.0);
operations.add("+");
operations.add("-");
operations.add("*");
operations.add("/");
}
private int lineCounter = 0;
public Generator() {
this.init();
}
private void init() {
}
public void generate() {
// Length 2 ###########################################################
boolean okay = false;
int lineCounter = 0;
StringBuilder sbDouble = new StringBuilder();
for (Double first : numbers) {
for (Double second : numbers) {
for (String operation : operations) {
if (first == second) {
continue;
}
if (operation.equals("/") && (first == 0.0 || second == 0.0)) {
continue;
}
double result = perform(first, operation, second);
okay = this.check(result, operation);
if (okay) {
++lineCounter;
sbDouble = new StringBuilder();
this.computeResultAsString(sbDouble, first, operation, second, result);
System.out.println(sbDouble.toString());
}
}
}
}
System.out.println("Compute with length 2: " + lineCounter + " lines");
// Length 2 ###########################################################
// Length 3 ###########################################################
okay = false;
lineCounter = 0;
sbDouble = new StringBuilder();
for (Double first : numbers) {
for (Double second : numbers) {
for (String operation1 : operations) {
if (first == second) {
continue;
}
if (operation1.equals("/") && (first == 0.0 || second == 0.0)) {
continue;
}
double result1 = perform(first, operation1, second);
okay = this.check(result1, operation1);
if (okay) {
for (Double third : numbers) {
for (String operation2 : operations) {
if (second == third) {
continue;
}
if (operation2.equals("/") && third == 0.0) {
continue;
}
double result2 = perform(result1, operation2, third);
okay = this.check(result2, operation2);
if (okay) {
++lineCounter;
sbDouble = new StringBuilder();
this.computeResultAsString(sbDouble, first, operation1, second, result1);
this.computeResultAsString(sbDouble, operation2, third, result2);
System.out.println(sbDouble.toString());
}
}
}
}
}
}
}
System.out.println("Compute with length 3: " + lineCounter + " lines");
// Length 3 ###########################################################
// Length 4 ###########################################################
okay = false;
lineCounter = 0;
sbDouble = new StringBuilder();
for (Double first : numbers) {
for (Double second : numbers) {
for (String operation1 : operations) {
if (first == second) {
continue;
}
if (operation1.equals("/") && (first == 0.0 || second == 0.0)) {
continue;
}
double result1 = perform(first, operation1, second);
okay = this.check(result1, operation1);
if (okay) {
for (Double third : numbers) {
for (String operation2 : operations) {
if (second == third) {
continue;
}
if (operation2.equals("/") && third == 0.0) {
continue;
}
double result2 = perform(result1, operation2, third);
okay = this.check(result2, operation2);
if (okay) {
for (Double forth : numbers) {
for (String operation3 : operations) {
if (third == forth) {
continue;
}
if (operation3.equals("/") && forth == 0.0) {
continue;
}
double result3 = perform(result2, operation3, forth);
okay = this.check(result3, operation3);
if (okay) {
++lineCounter;
sbDouble = new StringBuilder();
this.computeResultAsString(sbDouble, first, operation1, second, result1);
this.computeResultAsString(sbDouble, operation2, third, result2);
this.computeResultAsString(sbDouble, operation3, forth, result3);
System.out.println(sbDouble.toString());
}
}
}
}
}
}
}
}
}
}
System.out.println("Compute with length 4: " + lineCounter + " lines");
// Length 4 ###########################################################
}
private boolean check(double result, String operation) {
switch (operation) {
case "+":
case "-":
case "*": {
if (result > 0 && result <= 12) {
return true;
}
break;
}
case "/": {
if (
(Math.floor(result) == result)
&& (result >= 0 && result <= 12)
) {
return true;
}
break;
}
}
return false;
}
private double perform(double first, String operation, double second) {
double result = 0.0;
switch (operation) {
case "+": { result = first + second; break; }
case "-": { result = first - second; break; }
case "*": { result = first * second; break; }
case "/": { result = first / second; break; }
}
return result;
}
private void computeResultAsString(StringBuilder sbDouble, String operation, double second, double result) {
sbDouble.append(operation);
sbDouble.append(second);
sbDouble.append("(=");
sbDouble.append(result);
sbDouble.append(")");
}
private void computeResultAsString(StringBuilder sbDouble, double first, String operation, double second, double result) {
sbDouble.append(first);
sbDouble.append(operation);
sbDouble.append(second);
sbDouble.append("(=");
sbDouble.append(result);
sbDouble.append(")");
}
public static void main(String[] args) {
final Generator generator = new Generator();
generator.generate();
}
}
As you can see in your own code, for each increase in "length", you have to nest another block of the same code. With a dynamic length value, you can't do that.
Therefore, you move the block of code into a method, and pass in a parameter of how many more times it has to "nest", i.e. a remainingLength. Then the method can call itself with a decreasing value of remainingLength, until you get to 0.
Here is an example, using an enum for the operator.
public static void generate(int length) {
if (length <= 0)
throw new IllegalArgumentException();
StringBuilder expr = new StringBuilder();
for (int number = 0; number <= 12; number++) {
expr.append(number);
generate(expr, number, length - 1);
expr.setLength(0);
}
}
private static void generate(StringBuilder expr, int exprTotal, int remainingLength) {
if (remainingLength == 0) {
System.out.println(expr);
return;
}
final int exprLength = expr.length();
for (int number = 0; number <= 12; number++) {
if (number != exprTotal) {
for (Operator oper : Operator.values()) {
int total = oper.method.applyAsInt(exprTotal, number);
if (total >= 0 && total <= 12) {
expr.append(oper.symbol).append(number)
.append("(=").append(total).append(")");
generate(expr, total, remainingLength - 1);
expr.setLength(exprLength);
}
}
}
}
}
private enum Operator {
PLUS ('+', Math::addExact),
MINUS ('-', Math::subtractExact),
MULTIPLY('*', Math::multiplyExact),
DIVIDE ('/', Operator::divide);
final char symbol;
final IntBinaryOperator method;
private Operator(char symbol, IntBinaryOperator method) {
this.symbol = symbol;
this.method = method;
}
private static int divide(int left, int right) {
if (right == 0 || left % right != 0)
return -1/*No exact integer value*/;
return left / right;
}
}
Be aware that the number of permutations grow fast:
1: 13
2: 253
3: 5,206
4: 113,298
5: 2,583,682
6: 61,064,003
7: 1,480,508,933

Java: Using created string as loop parameter?

In short, the user will input a number (say 1 through 3). This will decide which range of numbers the loop should search through.
switch(input){
case 1:
searchTerm = "i<10 && i>5";
case 2:
searchTerm = "i>=10 && i<19";
case 3:
searchTerm = "i>19 && i<24";
}
while(searchTerm){
//some function
}
Is this possible? I I've not been able to find a way to use a string as search parameters.
EDIT: I don't think I did a very good job of explaining why I needed this. What is one to do if there are different numbers of parameters? For example:
case 1:
searchTerm = "i<5"
case 2:
searchTerm = "i>25 && i<29"
case 3:
searchTerm = "(i<50 && i>25) && (i>55 && i<75)"
case 4:
searchTerm = "(i<20 && i>15) && (i>300 && i<325) && (i>360 && i<380)
Then how does one do it? Multiple loops that call the same function?
The correct way to do this is to not use a string at all:
int min, max;
switch(input){
case 1: // i<10 && i>5
min = 6;
max = 10;
break; // to avoid follow-through to the next case
case 2: // i>=10 && i<19
min = 10;
max = 20;
break;
case 3: // i>19 && i<24
min = 20;
max = 25;
break;
default:
// You need something here in case the value entered wasn't 1-3
}
for (int i = min; i < max; ++i) {
// ...
}
Re your edit:
I don't think I did a very good job of explaining why I needed this. What is one to do if there are different numbers of parameters?
In that case, you'll have to use an expression evaluator (or write one, which is a non-trivial task). There's one in Spring, for instance (not recommending, just happened to hear about it). A search for "Java expression evaluator" should turn up some options.
Another alternative, which is somewhat amusing given that some folks mistook your question for a JavaScript question, is to use the JavaScript evaluator built into Java (either Rhino or Nashorn). E.g.: Live Example
import javax.script.*;
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
String searchTerm = "i >= 19 && i <= 24";
int i;
try {
i = 19;
engine.put("i", i);
while ((boolean)engine.eval(searchTerm)) {
System.out.println("i = " + i);
++i;
engine.put("i", i);
}
System.out.println("Done");
} catch (ScriptException scriptException) {
System.out.println("Failed with script error");
}
}
}
...but you'll still have the problem of determining what initial value to use for i, which I've hardcoded above.
In Java 8 you can select a lambda instead of String:
Predicate<Integer> searchTerm = (Integer v) -> false;
switch (input) {
case 1:
searchTerm = (Integer v) -> v < 10 && v > 5;
break;
case 2:
searchTerm = (Integer v) -> v >= 10 && v < 19;
break;
case 3:
searchTerm = (Integer v) -> v > 19 && v < 24;
break;
}
while (searchTerm.test(i)) {
...
}
You can create an enumeration as below.
public enum SearchTerms {
None(""),
Between6And9("i<10 && i>5"),
Between10And18("i>=10 && i<19"),
Between20And23("i>19 && i<24");
private final String stringValue;
SearchTerms(String stringValue) {
this.stringValue = stringValue;
}
public String getStringValue() {
return stringValue;
}
public static SearchTerms fromStringValue(String stringValue) {
for (SearchTerms searchTerm : values()) {
if (searchTerm.getStringValue().equalsIgnoreCase(stringValue)) {
return searchTerm;
}
}
return SearchTerms.None;
}
}
Usage:
SearchTerms searchTerm = SearchTerms.fromStringValue("i<10 && i>5");
switch(searchTerm) {
case Between6And9:
//dosomething
break;
}
You can use .eval() of JavaScript.
Also don't forget break; at the end of each case:
Check out this fiddle.
Here is the snippet.
function test(input, i) {
switch (input) { //input=1
case 1:
searchTerm = "i<10 && i>5"; //this will be 'searchTerm'
break;
case 2:
searchTerm = "i>=10 && i<19";
break;
case 3:
searchTerm = "i>19 && i<24";
break;
}
while (eval(searchTerm)) { //'searchTerm' converted to boolean expression
alert(i); // alert for i=7,8,9
i++;
}
}
test(1, 7); //pass input=1 and i=7

Categories