Questions regarding programming a single-line calculator in Java - java

I am currently a early CS student and have begun to start projects outside of class just to gain more experience. I thought I would try and design a calculator.
However, instead of using prompts like "Input a number" etc. I wanted to design one that would take an input of for example "1+2+3" and then output the answer.
I have made some progress, but I am stuck on how to make the calculator more flexible.
Scanner userInput = new Scanner(System.in);
String tempString = userInput.nextLine();
String calcString[] = tempString.split("");
Here, I take the user's input, 1+2+3 as a String that is then stored in tempString. I then split it and put it into the calcString array.
This works out fine, I get "1+2+3" when printing out all elements of calcString[].
for (i = 0; i <= calcString.length; i += 2) {
calcIntegers[i] = Integer.parseInt(calcString[i]);
}
I then convert the integer parts of calcString[] to actual integers by putting them into a integer array.
This gives me "1 0 2 0 3", where the zeroes are where the operators should eventually be.
if (calcString[1].equals("+") && calcString[3].equals("+")) {
int retVal = calcIntegers[0] + calcIntegers[2] + calcIntegers[4];
System.out.print(retVal);
}
This is where I am kind of stuck. This works out fine, but obviously isn't very flexible, as it doesn't account for multiple operators at the same like 1 / 2 * 3 - 4.
Furthermore, I'm not sure how to expand the calculator to take in longer lines. I have noticed a pattern where the even elements will contain numbers, and then odd elements contain the operators. However, I'm not sure how to implement this so that it will convert all even elements to their integer counterparts, and all the odd elements to their actual operators, then combine the two.
Hopefully you guys can throw me some tips or hints to help me with this! Thanks for your time, sorry for the somewhat long question.

Create the string to hold the expression :
String expr = "1 + 2 / 3 * 4"; //or something else
Use the String method .split() :
String tokens = expr.split(" ");
for loop through the tokens array and if you encounter a number add it to a stack. If you encounter an operator AND there are two numbers on the stack, pop them off and operate on them and then push back to the stack. Keep looping until no more tokens are available. At the end, there will only be one number left on the stack and that is the answer.
The "stack" in java can be represented by an ArrayList and you can add() to push items onto the stack and then you can use list.get(list.size()-1); list.remove(list.size()-1) as the pop.

You are taking input from user and it can be 2 digit number too.
so
for (i = 0; i <= calcString.length; i += 2) {
calcIntegers[i] = Integer.parseInt(calcString[i]);
}
will not work for 2 digit number as your modification is i+=2.
Better way to check for range of number for each char present in string. You can use condition based ASCII values.

Since you have separated your entire input into strings, what you should do is check where the operations appear in your calcString array.
You can use this regex to check if any particular String is an operation:
Pattern.matches("[+-[*/]]",operation )
where operation is a String value in calcString
Use this check to seperate values and operations, by first checking if any elements qualify this check. Then club together the values that do not qualify.
For example,
If user inputs
4*51/6-3
You should find that calcString[1],calcString[4] and calcString[6] are operations.
Then you should find the values you need to perform operations on by consolidating neighboring digits that are not separated by operations. In the above example, you must consolidate calcString[2] and calcString[3]
To consolidate such digits you can use a function like the following:
public int consolidate(int startPosition, int endPosition, ArrayList list)
{
int number = list.get(endPosition);
int power = 10;
for(int i=endPosition-1; i>=startPosition; i--)
{
number = number + (power*(list.get(i)));
power*=10;
}
return number;
}
where startPosition is the position where you encounter the first digit in the list, or immediately following an operation,
and endPosition is the last position in the list till which you have not encountered another operation.
Your ArrayList containing user input must also be passed as an input here!
In the example above you can consolidate calcString[2] and calcString[3] by calling:
consolidate(2,3,calcString)
Remember to verify that only integers exist between the mentioned positions in calcString!
REMEMBER!
You should account for a situation where the user enters multiple operations consecutively.
You need a priority processing algorithm based on the BODMAS (Bracket of, Division, Multiplication, Addition and Subtraction) or other mathematical rule of your preference.
Remember to specify that your program handles only +, -, * and /. And not power, root, etc. functions.
Take care of the data structures you are using according to the range of inputs you are expecting. A Java int will handle values in the range of +/- 2,147,483,647!

Related

Comparing two char arrays in Java

I am trying to compare two char arrays lexicographically, using loops and arrays only. I solved the task, however, I think my code is bulky and unnecessarily long and would like an advice on how to optimize it. I am a beginner. See code below:
//Compare Character Arrays Lexicographically
//Write a program that compares two char arrays lexicographically (letter by letter).
// Research how to convert string to char array.
Scanner scanner = new Scanner(System.in);
String word1 = scanner.nextLine();
String word2 = scanner.nextLine();
char[] firstArray = word1.toCharArray();
char[] secondArray = word2.toCharArray();
for (char element : firstArray) {
System.out.print(element + " ");
}
System.out.println();
for (char element : secondArray) {
System.out.print(element + " ");
}
System.out.println();
String s = String.valueOf(firstArray);
String b = String.valueOf(secondArray);
int result = s.compareTo(b);
if (result < 0) {
System.out.println("First");
} else if (result > 0) {
System.out.println("Second");
} else {
System.out.println("Equal");
}
}
}
I think its pretty normal. You've done it right. There's not much code to reduce here , best you can do is not write the two for loops to print the char arrays. Or if you are wanting to print the two arrays then maybe use System.out.println(Arrays.toString(array_name)); instead of two full dedicated for/for each loops. It does the same thing in the background but makes your code look a little bit cleaner and that's what you are looking for.
As commented by tgdavies, you schoolwork assignment was likely intended for you to compare characters in your own code rather than call String#compareTo.
In real life, sorting words alphabetically is quite complex because of various cultural norms across various languages and dialects. For real work, we rely on collation tools rather than write our own sorting code. For example, an e with the diacritical ’ may sort before or after an e without, depending on the cultural context.
But for a schoolwork assignment, the goal of the exercise is likely to have you compare each letter of each word by examining its code point number, the number assigned to identify each character defined in Unicode. These code point numbers are assigned by Unicode in roughly alphabetical order. This code point number ordering is not sufficient to do sorting in real work, but is presumably good enough for your assignment, especially for text using only basic American English using letters a-z/A-Z.
So, if the numbers are the same, move to the next character in each word. When you reach the nth letter that are not the same in both, then in overly simplistic terms, you know which comes after which alphabetically. If all the numbers are the same, the words are the same.
Another real world problem is the char type has been legacy since Java 5, essentially broken since Java 2. As a 16-bit value, char is physically incapable of representing most characters.
So instead of char arrays, use int arrays to hold code point integer numbers.
int[] firstWordCodePoints = firstWord.codePoints().toArray() ;

NZEC error in Hackerearth problem in java

I'm trying the solve this hacker earth problem https://www.hackerearth.com/practice/basic-programming/input-output/basics-of-input-output/practice-problems/algorithm/anagrams-651/description/
I have tried searching through the internet but couldn't find the ideal solution to solve my problem
This is my code:
String a = new String();
String b = new String();
a = sc.nextLine();
b = sc.nextLine();
int t = sc.nextInt();
int check = 0;
int againCheck =0;
for (int k =0; k<t; k++)
{
for (int i =0; i<a.length(); i++)
{
char ch = a.charAt(i);
for (int j =0; j<b.length(); j++)
{
check =0;
if (ch != b.charAt(j))
{
check=1;
}
}
againCheck += check;
}
}
System.out.println(againCheck*againCheck);
I expect the output to be 4, but it is showing the "NZEC" error
Can anyone help me, please?
The requirements state1 that the input is a number (N) followed by 2 x N lines. Your code is reading two strings followed by a number. It is probably throwing an InputMismatchException when it attempts to parse the 3rd line of input as a number.
Hints:
It pays to read the requirements carefully.
Read this article on CodeChef about how to debug a NZEC: https://discuss.codechef.com/t/tutorial-how-to-debug-an-nzec-error/11221. It explains techniques such as catching exceptions in your code and printing out a Java stacktrace so that you can see what is going wrong.
1 - Admittedly, the requirements are not crystal clear. But in the sample input the first line is a number.
As I've written in other answers as well, it is best to write your code like this when submitting on sites:
def myFunction():
try:
#MY LOGIC HERE
except Exception as E:
print("ERROR Occurred : {}".format(E))
This will clearly show you what error you are facing in each test case. For a site like hacker earth, that has several input problems in various test cases, this is a must.
Coming to your question, NZEC stands for : NON ZERO EXIT CODE
This could mean any and everything from input error to server earthquake.
Regardless of hacker-whatsoever.com I am going to give two useful things:
An easier algorithm, so you can code it yourself, becuase your algorithm will not work as you expect;
A Java 8+ solution with totally a different algorithm, more complex but more efficient.
SIMPLE ALGORITM
In you solution you have a tipical double for that you use to check for if every char in a is also in b. That part is good but the rest is discardable. Try to implement this:
For each character of a find the first occurence of that character in b
If there is a match, remove that character from a and b.
The number of remaining characters in both strings is the number of deletes you have to perform to them to transform them to strings that have the same characters, aka anagrams. So, return the sum of the lenght of a and b.
NOTE: It is important that you keep track of what you already encountered: with your approach you would have counted the same character several times!
As you can see it's just pseudo code, of a naive algorithm. It's just to give you a hint to help you with your studying. In fact this algorithm has a max complexity of O(n^2) (because of the nested loop), which is generally bad. Now, a better solution.
BETTER SOLUTION
My algorithm is just O(n). It works this way:
I build a map. (If you don't know what is it, to put it simple it's a data structure to store couples "key-value".) In this case the keys are characters, and the values are integer counters binded to the respective character.
Everytime a character is found in a its counter increases by 1;
Everytime a character is found in b its counter decreases by 1;
Now every counter represents the diffences between number of times its character is present in a and b. So, the sum of the absolute values of the counters is the solution!
To implement it actually add an entry to map whenever I find a character for the first time, instead of pre-costructing a map with the whole alphabet. I also abused with lambda expressions, so to give you a very different sight.
Here's the code:
import java.util.HashMap;
public class HackerEarthProblemSolver {
private static final String a = //your input string
b = //your input string
static int sum = 0; //the result, must be static because lambda
public static void main (String[] args){
HashMap<Character,Integer> map = new HashMap<>(); //creating the map
for (char c: a.toCharArray()){ //for each character in a
map.computeIfPresent(c, (k,i) -> i+1); //+1 to its counter
map.computeIfAbsent(c , k -> 1); //initialize its counter to 1 (0+1)
}
for (char c: b.toCharArray()){ //for each character in b
map.computeIfPresent(c, (k,i) -> i-1); //-1 to its counter
map.computeIfAbsent(c , k -> -1); //initialize its counter to -1 (0-1)
}
map.forEach((k,i) -> sum += Math.abs(i) ); //summing the absolute values of the counters
System.out.println(sum)
}
}
Basically both solutions just counts how many letters the two strings have in common, but with different approach.
Hope I helped!

Java string arrayList: Sorting the elements in descending order (like polynomials in math)

I'm still quite new to programming, so I'm sorry if I caused you to face palm.
Right now, I am trying to create parentheses-expander in Java. The current program can already expand the parentheses, but it can not simplify the results, because the terms are not in the descending order. I do understand that you could try to add the terms without re-ordering them by comparing the variables contained in each of the elements. However, I want the program to "show work" like a human, so I need the terms in descending order.
And for that, I want to create a method that, given a string arrayList, re-orders the elements in something like descending order for polynomials in math.
If any of the variables had exponents, the variable is just repeated to the number of the exponent.
for example:
X^2 = XX,
a^3 = aaa,
Z^5 = ZZZZZ
Also, there will be no negative exponents nor parentheses.
All elements have either + or - at the beginning(and no other operators after that).
All elements have a coefficient, even if it is 1.
Capital letters have higher importance than lower case letters, and elements with just numbers should be re-located to the very end.
I forgot the mathematical word for that, but the terms should be ordered in a interest of A, then B so on until Z, and then a,b,c,...so on.(I mean, terms with most A comes first, B second ,C third... up until z)
Coefficients and operators should be ignored.
For example, if the input was this:
[-1b,+3XX,-4AA,+1aaa,+20CCa,-9ABa,-9ABaa,+20CCCa,+3BBX,+1aab,+10]
Then I want the method to return the arrayList like:
[-4AA,-9ABaa,-9ABa,+3BBX,+20CCCa,+20CCa,+3XX,+1aaa,+1aab,-1b,+10]
I'm very much stuck right here. any help will be appreciated. If I didn't describe my problem clear enough, please let me know. I will clarify.
I believe wolfram alpha already has parentheses expanding capabilities. However, I still want to make this.
If anyone can help me with this, that will be amazing. Thanks in advance!
You have a couple of challenges that need to be dealt with individually:
How do I parse something like -1b into a format I can work with?
How do I sort by a custom sorting rule?
For the first part, your rule is very well-defined and the format is pretty simple. This lends itself well to using a regular expression to parse it:
Also, there will be no negative exponents nor parentheses. All elements have either + or - at the beginning(and no other operators after that). All elements have a coefficient, even if it is 1.
So a good regular expression format might be:
([-+]\d+)(\w+)?
This would result in two "capture groups". The first would be the numeric part, and the second would be the (optional) repeated string part.
After decomposing each entry into these two separate parts, it is pretty easy to come up with a set of rules for determining the sort order:
If both of them are numbers (having only the first part), then sort as numbers
If one of them is a number, and the other has letters, sort the number afterward.
If both have numbers and letters, sort according to the letters only using normal String sorting.
An easy way to do custom sorting is to write a custom Comparator class which would be used as an argument to the sort function. Combining all the ideas presented above that might look something like this:
public class PolynomialComparator implements Comparator<String> {
private static Pattern pattern = Pattern.compile("([-+]\\d+)(\\w+)?");
#Override
public int compare(String s1, String s2) {
if (s1 == null) throw new NullPointerException("s1");
if (s2 == null) throw new NullPointerException("s2");
int compare = 0;
Matcher m1 = pattern.matcher(s1);
Matcher m2 = pattern.matcher(s2);
if (!m1.matches()) throw new IllegalArgumentException("Invalid Polynomial format: " + s1);
if (!m2.matches()) throw new IllegalArgumentException("Invalid Polynomial format: " + s2);
int n1 = Integer.parseInt(m1.group(1));
int n2 = Integer.parseInt(m2.group(1));
String p1 = m1.group(2);
String p2 = m2.group(2);
if (p1 == null && p2 == null) { // Rule #1: just compare numbers
compare = n2 - n1;
} else if (p1 == null) { // Rule #2: always sort number last
compare = 1;
} else if (p2 == null) { // Rule #2: always sort non-number first
compare = -1;
} else { // Rule #3: compare the letters
compare = m1.group(2).compareTo(m2.group(2));
}
return compare;
}
}
Finally, to tie it all together, here is a simple program that correctly sorts your provided example using this Comparator (with the exception of your second and third entry which I believe is wrong in your example):
public static void main(String args[]){
String input = "[-1b,+3XX,-4AA,+1aaa,+20CCa,-9ABa,-9ABaa,+20CCCa,+3BBX,+1aab,+10]";
String[] array = input.substring(1, input.length() - 1).split(",");
Arrays.sort(array, new PolynomialComparator());
System.out.println("[" + String.join(",", array) + "]");
}
OUTPUT: [-4AA,-9ABa,-9ABaa,+3BBX,+20CCCa,+20CCa,+3XX,+1aaa,+1aab,-1b,+10]
Hopefully you can spend some time walking through this and learn a few ideas that will help you on your way. Cheers!

Checking if all digits appears in another array

I made this piece of code that should ask the user enter the length of first arrays that will contain how much numbers that he want, than recieving every number untill the amount is done.
after that he need to ask for the length of digits array, and than recieving the digits.
than, I need to check if all the numbers contain all the digits, if its true, print it, if not, print false.
In this code I already replace the int[] with string arrays, Because I think this is the way it whould work.
when I tried to make an Int arrays, with only single digit numbers, It works great, The problem comes when you want number like 22 with 2 digits, the checking breaks and not working.
String numInNumbersArray,
digitInDigitsArray;
int counterNumbers=0;
System.out.println("Please enter the length of the numbers array: ");
int numbersLength=s.nextInt();
String[] numbersArray=new String [numbersLength];
System.out.printf("Please enter %d numbers: ",numbersLength);
for(int i=0;i<numbersArray.length;i++){
numInNumbersArray=s.next();
numbersArray[i]=numInNumbersArray;
}
System.out.println("Please enter the length of the digits array: ");
int digitsLength=s.nextInt();
String[] digitsArray=new String [digitsLength];
System.out.printf("Please enter %d digits between 0 - 9 and - if you want: ",digitsLength);
for(int i=0;i<digitsArray.length;i++){
digitInDigitsArray=s.next();
digitsArray[i]=digitInDigitsArray;
}
for(int i=0;i<digitsArray.length;i++){
for(int j=0;j<numbersArray.length;j++){
if(numbersArray[j].equals(digitsArray[i])){
counterNumbers++;
}
}
}
if(counterNumbers==numbersArray.length){
System.out.println("true\n");
}else{
System.out.println("false\n");
}
So I obviously need a String array, But I have no idea how to continue from here to check every digit from a number. ( I cannot use advanced methods, Only simple checks).
Your help or tuning would be great. thanks.
EDIT: It must be string because it also maight contain '-' (negetive numbers)
to make it more clealry to understand I will add examples:
digits arrays for example : (1,2,-,3)
and numbers array : (1,-2,3)
this should return true.
and digits: (1,2,3)
numbers: (12,-3,123)
should return false.
You problem lies within your check to see if the arrays are equals.
Imagine if numbersArray = {"2", "2"} and digitsArray = {"2", "2"} like you stated above.
This loop:
for(int i=0;i<digitsArray.length;i++){
for(int j=0;j<numbersArray.length;j++){
if(numbersArray[j].equals(digitsArray[i])){
counterNumbers++;
}
}
}
will compare the first "2" - numbersArray[0] with digitsArray[0] AND digitsArray[1], making counterNumbers = 2. Then, the first for loop will process to i=1, where it will come the second "2" - numbersArray[1] with digitsArray[0] AND digitsArray[1] making counterNumbers = 4.
Do you see your fault here?
Here is a hint, you should be comparing each array "digit-by-digit" rather than comparing the first "digit" in numbersArray to all of the "digits" in digitsArray. NOTE: This hint is only useful if you have each array (numbersArray and digitsArray) in the same order. You should look into sorting them to ensure that.
Since this seems like a homework assignment i'll stop here and let you try to fix it yourself.

Text Arrays in Java

I'm working on a program for a class and was wondering if someone could point me in the right direction. I've worked with Java before, but it's been a while and I'm really rusty. The purpose of this program is to prompt a user to enter a phone number represented by letters (for example CALL HOME would be 225-5466), the program is then to display the phone number based on the letters entered.
We are supposed to store the letters entered by the user into an array and then convert those letters into the actual phone number. Here's what I'm getting stuck on at the moment, I've only worked with arrays consisting of numbers so am not sure how to set this one up. I'm assuming that each index would be one letter, but how would I break the string entered by the user down into individual char characters?
I'm still in the process of thinking through how this program should work and putting it on paper so haven't actually started coding yet, so I apologize for not having any code to share. But this is what I'm thinking would need to happen once the letter representation of the phone numbers were placed in the array:
Declare variables for each letter, like
int a = 1
int b = 1
int c = 1
int d = 2
etc. Or is there a more efficient way to do that? Then use if statements for each index like,
if [0] == a || b || c
[0] = 1
if [0] == d || e || f
[0] = 2
and so on. Like I said, I'm really rusty and am just trying to think my way through this right now before just throwing code at the screen haha. Any pointers would be much appreciated.
Just use String#toCharArray:
char[] characters = string.toCharArray();
You can then get the individual characters from a string.
You could use a series of if statements to see what characters map to what number. But there are more-elegant approaches. I am not sure if you have used Map<K, V>, but you could set up a Map<String, Integer> that maps a letter to its integer representation. Then you'd simply have to iterate over the characters in the string and look up their value.
Since this is homework, this is about as much information that I think is appropriate. Using what I have given you, you should be able to come up with an algorithm. Just start writing the code even if you don't know what the end result will look like. This will give you the following advantages:
Give you a clearer idea of the problem.
Will familiarize you with the problem-space.
Will help you visualize and understand your problem and the algorithm.
What you can do is to create a 2 dimensional array and methods to check the input against it. For example you can do the following:
Create an array numbers of length 10. Each index corresponds to a number you have to call.
Now each entry of the numbers array is an array of chars. So in the end you have something like this :
numbers = [['w/e you want for 0'],['a','b','c'],['d','e','f'], ['g','h','i'], ... etc ]
When you parse the input string you compare each character with a method like this:
private int letterToNumber(char c){
for(i = 0; i < numbers.length; i++)
if(contains(numbers[i], c) return i;
}
and your contains() method should be something like that
private boolean contains(char[] chars, char c){
for(char x : chars)
return(x == c)? true; false;
}

Categories