I'm trying to add some numbers from a string
For example the string is "5 + 3 +2". This should return 10
This is my code for getting the number of the operator is a "+"
int opIndex= expression.indexOf("+");
Double lhs = Double.parseDouble(expression.substring(0, opIndex));
Double rhs = Double.parseDouble(expression.substring(opIndex+1));
What I got in return is
lhs = 5 (which is what I wanted)
rhs = returned a string error (3+2);
How can I get number 3 only then do + 2 after the (5+3) or any other approach?
Thanks.
If you do things recursively with a list of things, always think in the following pattern:
handle the first element of the list
handle the rest of the list using a recursive call
So in the case of "5 + 3 +2", split off 5 and "+" and then pass the rest ("3+2") to the same method again.
It's also far easier to remove the spaces before you start.
public static void main(String[] args) {
String input = "5 + 3 + 2";
//remove spaces:
input = input.replaceAll(" +", "");
int r = evaluate(input);
System.out.println(r);
}
private static int evaluate(String s) {
int operatorIndex = s.indexOf('+');
if(operatorIndex == -1) {
//no operator found, s is the last number
//this is the base case that "ends" the recursion
return Integer.parseInt(s);
}
else {
//this is left hand side:
int operand = Integer.parseInt(s.substring(0, operatorIndex));
//this performs the actual addition of lhs and whatever rhs might be (here's where recursion comes in)
return operand + evaluate(s.substring(operatorIndex+1));
}
}
This code prints 10. It gets a more complex if you also want to support substraction, but you will figure it out.
The "RHS" string ends up being something like " 3 + 2". Your job is not to get the 3. Your job is to recurse: Give that string to your own algorithm, trust that it works.
That's how recursion works: You assume your algorithm already works, and then you write it, calling yourself, with the additional rule that you can only call yourself with a 'simpler' case (because otherwise it'll never end), and that you write code to deal with the simplest case explicitly (which in this case would presumably be if I hand your method just a number. If I hand it "5", it needs to return 5, and not recurse).
you can split the spring using the split method
String array[]=expression.split("+")
now itrate the aray and you can
Related
So at the input, a string contains different types of data. Basically, this is a string, int, and float. I check types through Float.parseFloat() and Integer.parseInt(). the Integer.parseInt() works correctly, yet Float.parseFloat() includes all the digits that are checked. How to avoid this?
The problem is that when checking for the float type, it also considers ints (output):
Hello my 50 name 4.5 is James, I 20 years old and I have 5.7 coins
Float 4
Int 2
String 12
public class TypeCountString {
public static void countTypeInString(String string){
String[] value = string.split(" ");
float ifFloat;
int ifInt;
String ifString;
int counter = 0;
// count Floats
for (String i: value){
try{
ifFloat = Float.parseFloat(i);
counter++;
continue;
} catch (NumberFormatException e){
}
}
System.out.println("Float " + counter);
//count ints
counter = 0;
for (String i: value){
try{
ifInt = Integer.parseInt(i);
counter++;
continue;
} catch (NumberFormatException e){
}
}
System.out.println("Int " + counter);
//counts strings
String stringOfStrings = string.replaceAll("[0-9.]","");
stringOfStrings = stringOfStrings.replaceAll(" "," ");
String[] value2 = stringOfStrings.split(" ");
System.out.println("String " + value2.length);
}
public static void main(String[] args) {
String string = "Hello my 50 name 4.5 is James, I 20 years old and i have 5.7 coins";
System.out.println(string);
countTypeInString(string);
}
}
As Integer is a sub-type of Float, Float will count in Integers into your float count. If you solely just want the number of float that is not integer, just take float count minus integer count.
Some tokens (like "50") are parseable both as integer and float. Your code gives both of them a chance, even though your intention is to only count each token as one type or the other (so count "50" as an integer, not as a float).
A simple fix could be to modify your float check to be:
make sure that i can pass Float.parseFloat(), and
confirm that i contains a decimal point
That code edit could look like this:
Float.parseFloat(i);
if (i.contains(".")) {
counter++;
continue;
}
Or, as a more involved alternative, instead of checking all input tokens for floats, then re-checking all input tokens for integers, I would take a different approach.
First, I would change the code to stop checking the entire input string repeatedly. This is helpful for 2nd part below, but also cleans up an unnecessary inefficiency of re-checking tokens even if you've already identified their data type. If you had a large number of tokens, it's wasteful to try parsing all of them as float, then try all of them as integer, then try a third time to count plain strings.
Second, since you would be checking (and counting) each token only one time, you could:
check for integer (before float) – if it passes Integer.parseInt(), increment that counter and move on to the next token
if it doesn't parse as integer, make an attempt to parse that token as float – just Float.parseFloat() without looking for decimal; if it worked then bump counter, move to next token
if it doesn't parse as integer or float, you know it's a String so simply bump the counter, then next token
As others have already said, since int is a subset of float, you can always parse a string representing an int as a float, while the opposite is not true. In fact, if the parsing string contains a decimal separator and you attempt to parse it as an int, you'll get a NumberFormatException.
However, you could use this behavior to your advantage and try to parse each string to the data type with minimal representation (int) and gradually increasing it as the parsing fails, until you reach the most generic representation (String). In your case, you could start to parse each string to int, if it fails proceed to float and ultimately to String if the float parsing doesn't work either.
Here is a possible implementation:
public class Main {
public static void main(String[] args) {
countTypesInString();
}
public static void countTypesInString() {
String str = "Hello my 50 name 4.5 is James, I 20 years old and i have 5.7 coins";
String[] vetStr = str.split("\\s+");
List<Integer> listInt = new ArrayList<>();
List<Float> listFloat = new ArrayList<>();
List<String> listStr = new ArrayList<>();
for (String s : vetStr) {
try {
listInt.add(Integer.parseInt(s));
} catch (NumberFormatException exInt) {
try {
listFloat.add(Float.parseFloat(s));
} catch (NumberFormatException exFloat) {
listStr.add(s);
}
}
}
System.out.println("Number of ints: " + listInt.size() + " => " + listInt);
System.out.println("Number of floats: " + listFloat.size() + " => " + listFloat);
System.out.println("Number of strings: " + listStr.size() + " => " + listStr);
}
}
Output
Number of ints: 2 => [50, 20]
Number of floats: 2 => [4.5, 5.7]
Number of strings: 12 => [Hello, my, name, is, James,, I, years, old, and, i, have, coins]
Side note: for real number representation, the double type is a better choice. In fact, by default Java treats every literal representing a real number as a double rather than a float. In the snippet above I've kept using float to maintain my code as close as possible to the original.
I am building a basic calculator in Java and have a few requirements to meet for it. it takes a math expression input from the user example. 3 * 5 ^ 5 (must be separated by spaces).
I'm having trouble figuring out how to pass the basic math expression input string math to the isNumber function and then in that function checking the first [0] spot of the string and every 4th spot (since spaces are still in there?) after for a double. I can do it if I turn math into a string array, but the requirements specifically said I cannot turn string math into an array until afterwards. I know if I can figure this out, then it shouldn't be hard to make an operator validation function and do the same for the spots of the input...
here is my current progress on the program.
import java.util.Scanner;
/**
*
* #author
*/
public class Calculator2 {
static ArrayList<String> validOperators = new ArrayList<String>(){{
add("^");
add("*");
add("/");
add("+");
add("-");
}};
public static void main(String[] args) {
System.out.println("This is a text based calculator!");
Scanner in = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("Enter a math expression ot type quit to exit: ");
String math = in.nextLine();
if ("quit".equalsIgnoreCase(math)) {
System.out.print("Quitting");
break;
}
if (isOperator(math)){
if (isNumber(math)){
String[] splitExpression = math.split("\\s+");
if(isValidExpression(splitExpression)){
for (int i=0; i<splitExpression.length; i++){
System.out.println(splitExpression[i]);
}
System.out.println("Number of tokens: " + splitExpression.length);
}
}else {
System.out.println("invalid expression!");
}
}else{
System.out.println("please use valid operators");
}
}
}
public static boolean isNumber(String number){
return
}
} ```
Numbers can be variable length, there can be multiple spaces - your approach (which involves things like 'check the 4th character') cannot work - you cannot work in absolute positions like this. It must be relative.
The usual approach is to realize that you've constructed an actual grammar here, and it can get quite complicated (toss in the ability to write parentheses and it's quite complicated indeed). Seems simple, but it just isn't.
Generally, you FIRST tokenize, which turns your stream of characters, into a stream of nodes. + is a node. So is 1.21398123. Nodes know what kind of thing they represent.
Then, you turn the stream of nodes into a tree. Then you calculate the result by going through the tree, from the leaves all the way up to the root.
i,e, this:
"10 * (2+3)"
is first turned into:
List.of(
NumericNode.of(10),
Operator.MULTIPLY,
Operator.OPEN_PAREN,
NumericNode.of(2),
Operator.ADD,
NumericNode.of(3),
Operator.CLOSE_PAREN);
Then that is turned into:
*
/ \
10 +
/ \
2 3
And that you can then trivially 'resolve' into 50 by collapsing nodes recursively.
As you can probably tell once you break it down like this: Not trivial.
You can search the web for tokenizers and parser tech on how to do this job. It'll take some reading.
All I really need to know is if the function I am using is recursive or if the method simply doesnt get called within itself.
In my code, I have a helper function to reverse the second word and I put a toLowerCase in order to be able to compare words even if there are any random capitals.
Is this recursion or is it just a function that compares the two?
import java.util.Scanner;
public class isReverse {
public static void main(String[] args) {
isReverse rev = new isReverse();
Scanner in = new Scanner(System.in);
System.out.println("Please enter a word: ");
String a = in.nextLine();
System.out.println("Please Enter a second word to compare: ");
String b = in.nextLine();
System.out.println(rev.isReverse(a, b));
}
String rev = "";
public boolean isReverse(String wordA, String wordB){
String fword = wordA.replaceAll("\\s+", "").toLowerCase();
String clean2 = wordB.replaceAll("\\s+", "").toLowerCase();
String reverse = revString(clean2);
if(fword.length() == 0){
return false;
}
if (fword.equals(reverse)){
return true;
}
if (!reverse.equals(fword)){
return false;
}
else
return isReverse(fword,reverse);
}
public String revString(String sequence) {
String input = sequence;
StringBuilder order = new StringBuilder();
order.append(input);
order = order.reverse();
rev = order.toString();
return rev;
}
}
As far as your question is concerned, your code is not behaving like a recursive function because your code is not entering into the last else condition. For recursion to work you need to have:
a base case(if there is no base case the recursion will go on forever)
a recursive case(this is where you kind of reduce the original problem)
But my comment about your code:
If you're doing the actual reverse logic you don't need to use recursion just to check if the original string and the reverse string are the same. These is purely an algorithm problem so here is the way to solve the problem:
If the length of the given input is 1 then the reverse is the same.
else:
check the first and last chars of the string, if they are equal, then you need to remove those two chars and check if the rest of the string is a palindrome. This is the actual recursive step.
else the string is not a palindrome.
Technically? Well, you are calling a method from within itself, so, technically, yeah.
Pragmatically? No. The recursive call part will never be invoked.
Your code does this: I have 2 words. If the words are equal to each other, stop and do something. if they are not equal to each other, stop and do something. Otherwise, recurse.
And that's where it falls apart: It'll never recurse - either the words are equal, or they are not.
The general idea behind a recursive function is three-fold:
The method (java-ese for 'function') calls itself.
Upon each call to itself, the parameters passed are progressing to an end state - they become smaller or trend towards a stop value such as 0.
There are edge cases where the function does not call itself, and returns instead (the answer for the smallest/zero-est inputs does not require recursion and is trivial).
You're missing the #2 part here. Presumably, this is what you'd want for a recursive approach. Forget about revString, delete that entirely. Do this instead:
If both inputs are completely empty, return true (That's the #3 - edge cases part).
If one of the two inputs is empty but the other one is not, false. (Still working on #3)
If the first character of the input string is NOT equal to the last character of the output string, false. (Still #3).
Now lop the first char off of the first input and the last off of the latter (Working on #2 now - by shortening the strings we're inevitably progressing towards an end no matter what)
now call ourself, with these new lopped-down strings (That'll be #1).
That would be a recursive approach to the problem. It's more complicated than for loops, but, then, recursive functions often are.
Actually this is not a recursing. All you need is just:
Check that both string have the same length
Iteratively check letters from 0 to n from the first string and from n to 0 from the second string. If they equal, then go to the next iteration (recutsion) or return fail otherqwise.
// here do not check signature of the public method
public static boolean isReverse(String one, String two) {
return isReverse(one, 0, two, two.length() - 1);
}
// support method has two additional counters to check letters to be equal
private static boolean isReverse(String one, int i, String two, int j) {
if (i == one.length())
return j == -1;
if (j == two.length())
return i == -1;
// if not equal, then strings are not equal
if (one.charAt(i) != two.charAt(j))
return false;
// go to the next recursion to check next letters
return isReverse(one, i + 1, two, j - 1);
}
Let's say I am given a list of String fragments. Two fragments can be concatenated on their overlapping substrings.
e.g.
"sad" and "den" = "saden"
"fat" and "cat" = cannot be combined.
Sample input:
aw was poq qo
Sample output:
awas poqo
So, what's the best way to write a method which find the longest string that can be made by combining the strings in a list. If the string is infinite the output should be "infinite".
public class StringUtil {
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (int i = 0; i < fragments.size(); i++) {
char last = (char) (fragments.get(i).length() - 1);
if (Character.toString(last).equals(fragments.get(i).substring(0))) {
combined.append(fragments.get(i)).append(fragments.get(i+1));
}
}
return combined.toString();
}
}
Here's my JUnit test:
public class StringUtilTest {
#Test
public void combine() {
List<String> fragments = new ArrayList<String>();
fragments.add("aw");
fragments.add("was");
fragments.add("poq");
fragments.add("qo");
String result = StringUtil.combine(fragments);
assertEquals("awas poqo", result);
}
}
This code doesn't seem to be working on my end... It returning an empty string:
org.junit.ComparisonFailure: expected:<[awas poqo]> but was:<[]>
How can I get this to work? And also how can I get it to check for infinite strings?
I don't understand how fragments.get(i).length() - 1 is supposed to be a char. You clearly casted it on purpose, but I can't for the life of me tell what that purpose is. A string of length < 63 will be converted to an ASCII (Unicode?) character that isn't a letter.
I'm thinking you meant to compare the last character in one fragment to the first character in another, but I don't think that's what that code is doing.
My helpful answer is to undo some of the method chaining (function().otherFunction()), store the results in temporary variables, and step through it with a debugger. Break the problem down into small steps that you understand and verify the code is doing what you think it SHOULD be doing at each step. Once it works, then go back to chaining.
Edit: ok I'm bored and I like teaching. This smells like homework so I won't give you any code.
1) method chaining is just convenience. You could (and should) do:
String tempString = fragments.get(i);
int lengthOfString = tempString.length() - 1;
char lastChar = (char) lengthOfString;//WRONG
Etc.
This lets you SEE the intermediate steps, and THINK about what you are doing. You are literally taking the length of a string, say 3, and converting that Integer to a Char. You really want the last character in the string. When you don't use method chaining, you are forced to declare a Type of intermediate variable, which of course forces you to think about what the method ACTUALLY RETURNS. And this is why I told you to forgo method chaining until you are familiar with the functions.
2) I'm guessing at the point you wrote the function, the compiler complained that it couldn't implicitly cast to char from int. You then explicitly cast to a char to get it to shut up and compile. And now you are trying to figure out why it's failing at run time. The lesson is to listen to the compiler while you are learning. If it's complaining, you're messing something up.
3) I knew there was something else. Debugging. If you want to code, you'll need to learn how to do this. Most IDE's will give you an option to set a break point. Learn how to use this feature and "step through" your code line by line. THINK about exactly what step you are doing. Write down the algorithm for a short two letter pair, and execute it by hand on paper, one step at a time. Then look at what the code DOES, step by step, until you see somewhere it does something that you don't think is right. Finally, fix the section that isn't giving you the desired result.
Looking at your unit test, the answer seems to be quite simple.
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (String fragment : fragments) {
if (combined.length() == 0) {
combined.append(fragment);
} else if (combined.charAt(combined.length() - 1) == fragment.charAt(0)) {
combined.append(fragment.substring(1));
} else {
combined.append(" " + fragment);
}
}
return combined.toString();
}
But seeing at your inqusition example, you might be looking for something like this,
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (String fragment : fragments) {
if (combined.length() == 0) {
combined.append(fragment);
} else if (combined.charAt(combined.length() - 1) == fragment.charAt(0)) {
int i = 1;
while (i < fragment.length() && i < combined.length() && combined.charAt(combined.length() - i - 1) == fragment.charAt(i))
i++;
combined.append(fragment.substring(i));
} else {
combined.append(" " + fragment);
}
}
return combined.toString();
}
But note that for your test, it will generate aws poq which seems to be logical.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
EDITED
I have this kind of string
"A-B-C-D"
"B-C-A"
"D-A"
"B-A-D"
"D-A-B-C"
Now my problem is if the user input has a value of "A-C" or "C-A" the numbers 1,2,5 will be my output because the those numbers has a value "A-C" if for example the user has a input value of either of this three "A-B-D","B-A-D","A-D-B" the the output will be 1,4,5. hope it clears the question
Note:
the search sequence depends on user input and i want it to be more efficient because I have 10 thousand of data I don't want to use as much loop as possible.
This might change based on you needs to have the String in the exact pattern you have it or not, but REALLY simply...
public class Simple {
public static void main(String[] args) {
System.out.println("1. " + matches("A-B-C-D"));
System.out.println("2. " + matches("B-C-A"));
System.out.println("3. " + matches("D-A"));
System.out.println("4. " + matches("B-A-D"));
System.out.println("5. " + matches("D-A-B-C"));
}
public static boolean matches(String value) {
return value.contains("A") && value.contains("C");
}
}
Which outputs
1. true
2. true
3. false
4. false
5. true
Extended example using variable matchers
So, the basic idea is to provide some kind of list of values to be matched against. This example simply uses a String varargs (or String array), but it wouldn't be hard to make it use something like List
public class Simple {
public static void main(String[] args) {
String[] match = new String[]{"A", "D", "C"};
System.out.println("1. " + matches("A-B-C-D", match));
System.out.println("2. " + matches("B-C-A", match));
System.out.println("3. " + matches("D-A", match));
System.out.println("4. " + matches("B-A-D", match));
System.out.println("5. " + matches("D-A-B-C", match));
}
public static boolean matches(String value, String... matches) {
boolean doesMatch = true;
for (String match : matches) {
if (!value.contains(match)) {
doesMatch = false;
break;
}
}
return doesMatch;
}
}
This outputs...
1. true
2. false
3. false
4. false
5. true
Use an array and go through each index and see if it contains "C-A" or "A-C" then if it does print the number.
String stringArray[] = {"A-B-C-D", "B-C-A", "D-A", "B-A-D", "D-A-B-C"};
for(int i = 0; i < stringArray.length; i++) {
String pattern = ".*C-.*A.*";
String pattern2 = ".*A-.*C.*";
if(stringArray[i].matches(pattern) || stringArray[i].matches(pattern2))
System.out.println(i + 1);
}
Edit: This applies to an older version of the OP that was unclear about finding the sequence in order; and so this searches for sequences in order, which isn't correct now.
There are many options. Below I outline one approach that tokenizes the strings first, and another that uses a simple regex generated from the input string.
Approach 1: Parsing Strings
Start by parsing each String into an array of substrings, that will make this all easier to work with. You may want to parse each of the strings when you originally read them instead of every time you need to:
String myString = "A-B-C-D";
String[] sequence = myString.split("-");
Next, consider using an List<String> instead of a String[], because it will make the rest of this a bit easier (you'll see). So, instead of the above:
String myString = "A-B-C-D";
List<String> sequence = Arrays.asList(myString.split("-"));
Now the problem becomes checking if two of these arrays match:
public static boolean containsSequence (List<String> searchIn, List<String> searchFor) {
}
You need to check both directions, but you can simply reverse the array and reduce this problem further to just checking the forward direction (there are certainly ways to do this and avoid the copy but they can get complicated and it's only worth it if you have high performance requirements):
public static boolean containsSequence (List<String> searchIn, List<String> searchFor) {
// first check forward
if (containsSequenceForward(searchIn, searchFor))
return true;
// now check in reverse
List<String> reversedSearchFor = new ArrayList<String>(searchFor);
Collections.reverse(reversedSearchFor);
return containsSequenceForward(searchIn, reversedSearchFor);
}
public static boolean containsSequenceForward (List<String> searchIn, List<String> searchFor) {
}
// usage example:
public static void example () {
List<String> searchIn = Arrays.asList("D-A-B-C".split("-"));
List<String> searchFor = Arrays.asList("A-C".split("-"));
boolean contained = containsSequence(searchIn, searchFor);
}
Now you just need to implement containsSequenceForward. I'd like you to do this yourself, but I will provide an algorithm as a hint:
Start at the beginning of searchIn and searchFor.
Go through searchIn one element at a time.
When you find the current element of searchFor in searchIn, advance searchFor to next element.
If you hit the end of searchFor you've found the sequence.
If you hit the end of searchIn but not searchFor, then the sequence doesn't match.
Now you have the ability to check if one sequence contains another in any order. To apply it to your entire collection, I recommend preparsing all of the strings into a List<String> once at the start, then you can go through each of those using the above algorithm.
There are many alternative options. For example, you could use indexOf on searchIn to find the each element in searchFor and make sure the indices are in increasing order.
Approach 2: Regular Expressions
Another option here is to use a regular expression to find the search sequence in the source string. You can build the regular expression dynamically from the search sequence quite easily:
String searchIn = "D-C-B-A";
String searchFor = "C-A";
String searchForPattern = searchFor.replace("-", ".*"); // yields "C.*A"
if (searchIn.matches(".*" + searchForPattern + ".*"))
/* then it matches forwards */;
Then to match in reverse, if the forward match fails, you can just reverse searchFor and repeat:
String searchForReverse = new StringBuilder(searchFor).reverse().toString();
String searchForReversePattern = searchForReverse.replace("-", ".*"); // yields "A.*C"
if (searchIn.matches(".*" + searchForReversePattern + ".*"))
/* then it matches backwards */;
Note that this particular regex solution assumes that each element is only one character long.
Also both of the above approaches assume case-sensitive matches -- to make the first case-insensitive I would just convert the strings to lowercase before parsing. For the second you can use a case-insensitive regex.
Hope that helps. Work it out on a piece of paper if you have to.
The general take home point here is it helps to reduce these problems to their smallest components first.
Call this function on every string you wish to check. If it returns true, add that string to your result set.
boolean matches(String s, char[] chars) {
for(char c : chars) {
if (s.indexOf(c) == -1) {
return false;
}
}
return true;
}