I'm slightly confused on this test question. I made a chart of the values of i , j, and the string. I got "nbearig", but my runtime is printing out numbers. I'm not sure where I went wrong. ++i , --j means that they were incre/decremented before the code after the for loop right?
public class AlGore {
public static void main(String[] args) {
String mystery = "mnerigpaba";
String solved = "";
int len = mystery.length();
for (int i = 0, j = len - 1; i < len/2; ++i, --j) {
solved += mystery.charAt(i) + mystery.charAt(j);
}
System.out.println(solved);
}
}
I'm not sure where I went wrong. ++i , --j means that they were incre/decremented before the code after the for loop right?
1) They were preincremented / predecremented respectively.
2) It happened after each execution of the loop body.
my compiler is printing out numbers.
No it isn't. The compiler is compiling your code!!! The JVM is printing numbers ... when you run the code.
To understand the reason why, take a careful look at this:
solved += mystery.charAt(i) + mystery.charAt(j);
This is equivalent to
solved = solved + ( mystery.charAt(i) + mystery.charAt(j) );
Now the expression in brackets performs a numeric addition of a character to a character. According to the rules of Java expressions, that gives an int value. So the entire expression becomes:
solved = String.concat(
solved,
Integer.toString(mystery.charAt(i) + mystery.charAt(j));
I thought that the charAt(i) function will return a string?
No. It returns a char ... just like the method name "charAt" implies. String and char are fundamentally different types.
Comment: That is a good exam question, it tests how well you understand loops, and how well you understand Java expression semantics.
You are performing integer math (because char is an integral type),
// solved += mystery.charAt(i) + mystery.charAt(j);
solved += Character.toString(mystery.charAt(i))
+ Character.toString(mystery.charAt(j));
That way you are performing String concatenation.
mystery.charAt(i) + mystery.charAt(j); will add the numeric values of those two characters. You can force string concatenation by adding "" + before:
solved += "" + mystery.charAt(i) + mystery.charAt(j);
Related
This question already has answers here:
concatenating string and numbers Java
(7 answers)
Closed 1 year ago.
Consider the following code (excerpt of main method):
String str = "The result: ";
int c = 5;
int k = 3;
System.out.println(str + c + k); // This would concatenate the all values, i.e. "The result: 53"
If the only thing allowed to be modified is within System.out.println(), is it possible to concatenate str to the sum of k and c?
Yes.
System.out.println(str + (c + k));
You can change order of execution by adding parentheses (same way as in math).
Indeed, as #talex said, you may use this single line code.
Yet, I think that this additude is a bit confusing, and may cause the code to be unreadable.
A better practice would be:
String str = "The result: ";
int c = 5;
int k = 3;
int result = c + k;
System.out.println(str + result);
This way, the code is more readable, and the order of execution will not confuse the programmers that read this code.
Yes
you should have use parentheses around sum of integers
System.out.println(str + (c + k));
I am getting the "Must be an array type but it resolved to string" error in my code. It also says that i (in the code below) cannot be resolved to a variable which I don't get.
public class DNAcgcount{
public double ratio(String dna){
int count=0;
for (int i=0;i<dna.length();i++);
if (dna[i]== "c"){
count+= 1;
if (dna[i]=="g"){
count+=1;
double answer = count/dna.length();
return answer;
}
}
}
}
Could you guys please help me figure out where the problem lies? I'm new to coding in Java so I am not entirely comfortable with the format yet.
Thanks a lot,
Junaid
You cannot access a String's character using subscript (dna[i]). Use charAt instead:
dna.charAt(i) == 'c'
Also, "c" is a String, 'c' is a char.
One more thing - integer division ( e.g. int_a / int_b ) results in an int, and so you lose accuracy, instead - cast one of the ints to double:
double answer = count/(double)dna.length();
Use {} to define the scope of the loop. Also, as others already pointed out, use charAt instead of [] and use ' for characters, and use floating point division for the ratio.
for (int i = 0; i < dna.length(); i++) {
if (dna.charAt(i) == 'c') {
count += 1;
}
if (dna.charAt(i) == 'g') {
count += 1;
}
}
Or a bit shorter, use || to or the two clauses together
if (dna.charAt(i) == 'c' || dna.charAt(i) == 'g') {
count += 1;
}
I think you are currently a bit weak at brackets , this is what i understood from your code and corrected it;
public class DNAcgcount{
public double ratio(String dna){
int count=0;
for (int i=0;i<dna.length();i++){
if (dna.charAt(i)== 'c')
count+= 1;
if (dna.charAt(i)=='g')
count+=1;
}
double answer = count/(double)dna.length();
return answer;
}
}
After if we have to close the brackets when what you want in if is finished . I think you wanted count to be the number of time c or g is present in the dna.
You also did some other mistakes like you have to use 'c' and 'g' instead of "c" and "g" if you are using .charAt(i) because it will be treated like a character and then only you can compare .
You may view this link
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html
and you may also have a look at works you can do with string like charAt.
It seems like that you have a few problems with the main syntax of basic java functions like loops or if-else statement. Click here for a good tutorial on these.
You must correct your for-loop and your if-statement:
for(int i=0;i<dna.length();i++){
if(...){
...;
}
if(...){
...;
}
}
Now you wont get the Cant be resolved to a variable... exception.
Second thing is the usage of your string. You have to use it like this:
for(int i=0;i<dna.length();i++){
if(dna.charAt(i) == 'c'){
count += 1;
}
if(dna.charAt(i) == 'g'){
count += 1;
}
}
Now all your exceptions should be eleminated.
Your problem is with syntax dna[i], dna is a string and you access it as it would be an array by []. Use dna.charAt(i); instead.
You using String incorrectly. Instead of accessing via [] use dna.charAt(i).
Altough logically a string is an array of characters in Java a String type is a class (which means it has attributes and methods) and not a typical array.
And if you want to compare a single character to another enclose it with '' instead of "":
if (dna.charAt(i) == 'c')
.
.
There are two errors:
count should be double or should be casted do double answer = (double)count / dna.length();
and as mentioned above you should replace dna[i] with dna.charAt(i)
Let's say there has a string like " world ". This String only has the blank at front and end. Is the trim() faster than replace()?
I used the replace once and my mentor said don't use it since the trim() probably faster.
If not, what's the advantage of trim() than replace()?
If we look at the source code for the methods:
replace():
public String replace(CharSequence target, CharSequence replacement) {
String tgtStr = target.toString();
String replStr = replacement.toString();
int j = indexOf(tgtStr);
if (j < 0) {
return this;
}
int tgtLen = tgtStr.length();
int tgtLen1 = Math.max(tgtLen, 1);
int thisLen = length();
int newLenHint = thisLen - tgtLen + replStr.length();
if (newLenHint < 0) {
throw new OutOfMemoryError();
}
StringBuilder sb = new StringBuilder(newLenHint);
int i = 0;
do {
sb.append(this, i, j).append(replStr);
i = j + tgtLen;
} while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
return sb.append(this, i, thisLen).toString()
}
Vs trim():
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
As you can see replace() calls multiple other methods and iterates throughout the entire String, while trim() simply iterates over the beginning and ending of the String until the character isn't a white space. So in the single respect of trying to only remove white space before and after a word, trim() is more efficient.
We can run some benchmarks on this:
public static void main(String[] args) {
long testStartTime = System.nanoTime();;
trimTest();
long trimTestTime = System.nanoTime() - testStartTime;
testStartTime = System.nanoTime();
replaceTest();
long replaceTime = System.nanoTime() - testStartTime;
System.out.println("Time for trim(): " + trimTestTime);
System.out.println("Time for replace(): " + replaceTime);
}
public static void trimTest() {
for(int i = 0; i < 1000000; i ++) {
new String(" string ").trim();
}
}
public static void replaceTest() {
for(int i = 0; i < 1000000; i ++) {
new String(" string ").replace(" ", "");
}
}
Output:
Time for trim(): 53303903
Time for replace(): 485536597
//432,232,694 difference
Assuming that the people writing the Java library code are doing a good job1, you can assume that a special purpose method (like trim()) will be as fast, and probably faster than a general purpose method (like replace(...)) doing the same thing.
Two reasons:
If the special purpose method is slower, its implementation can be rewritten as equivalent calls to the general purpose one, making the performance equivalent in most cases. A competent programmer will do this because it reduces maintenance costs.
In the special purpose method, it is likely that there will be optimizations that can be made that don't apply in the general-purpose case.
In this case we know that trim() only needs to look at the start and end of the string ... whereas replace(...) needs to look at all of the characters in the string. (We can infer this from the description of what the respective methods do.)
If we assume "competence" then we can infer that the developers will have done the analysis and not implemented trim() sub-optimally2; i.e. they won't code trim() to examine all characters.
There is another reason to use the special purpose method over the general purpose. It makes your code simpler, easier to read, and easier to inspect for correctness. This may well be more important than performance.
This clearly applies in the case of trim() versus replace(...).
1 - We can in this case. There are lots of eyes looking at this code, and lots of people who will complain loudly about egregious performance issues.
2 - Unfortunately, it is not always as straightforward as this. A library method needs to be optimized for "typical" behavior, but it also needs to avoid pathological performance in edge-cases. It is not always possible to achieve both things.
trim() is definitely faster to type, yes. It doesn't take any parameters.
It is also much faster to understand what you where trying to do. You were trying to trim the string, rather than replacing all the spaces it contains with the empty string, knowing from other context that there is only space at the beginning and the end of the string.
Indeed much faster no matter how you look at it. Don't complicate the life of the persons who're trying to read your code. Most of the time, it will be you months later, or at least someone you don't hate.
Trim will prune the outter characters until they are non white space. I believe they trim space, tab, and new lines.
Replace will scan the entire string (so, it could be a sentense) and would replace inner " " with "", essentially compressing them together.
They have different use cases though, obviously 1 is to clean up user input where the other is to update a string where matches are found with something else.
That being said, run times: Replace will run in N time, as it will look for all matching characters. Trim will run in O(N), but most likely a just a few characters off of each end.
The idea behind trim i think came around from people would would type and input things but accidentally press space before submitting their forms, essentially trying to save the field "Foo " instead of "Foo"
s.trim() shortens a String s. This means no characters has to be moved from an index to another. It starts at the first character (s.toCharArray()[0]) of the String and shortens the String character by character until the first non-whitespace character occurs. It works the same way to shorten the String at the end. So it compresses the String. If a String has no leading and trailing whitespace trim will be ready after checking the first and the last character.
In case of " world ".trim() two steps are needed: one to remove the first leading whitespace as it is on the first index and the the second to remove the last whitespace as it is on the last index.
" world ".replace(" ", "") will need at least n = " world ".length() steps. It has to check every character if it has to be replaced. But if we take into account that the implementation of String.replace(...) needs to compile a Pattern, build a Matcher and then to replace all the matched regions it's seems far complex comparing to shorten a String.
We also have to consider that " world ".replace(" ", "") does not replace whitespaces but only the String " ". Since String replace(CharSequence target, CharSequence replacement) compiles the target using Pattern.LITERAL we cannot use the character class \s. To be more accurate we would have to compare " world ".trim() to " world ".replaceAll("\\s", ""). It is still not the same because a whitespace in String trim() is defined as c <= ' ' for each c in s.toCharArray().
Summarizing: String.trim() should be faster - especially for long strings
The description how the methods work is based on the implementation of String in Java 8. But implementations can change.
But the question should be: What do you intent to do with the string? Do you want to trim it or to replace some characters? According to it use the corresponding method.
I am very sorry if this is a basic question which has been answered before (I tried looking but I did not find anything)
I am trying to write the following Java method:
String winningCard(String trick, char trump) {
StringBuilder sb = new StringBuilder();
char suit;
char rank;
for(int i = 1; i < trick.length(); i+=2) {
if(trick.charAt(i) == trump) {
suit = trick.charAt(i);
rank = trick.charAt(i-1);
sb.append(rank + suit); //issue here, returns a weird number
break;
}
}
String result = sb.toString();
return result;
}
When called with these arguments "8s7hQd", 'h' for example, it is supposed to return "7h".
If I change the StringBuilder to only append either the suit or the rank, it does it just fine, but if I put it the way it is above it returns "159" which I believe has something to do with the unicode encoding.
I'd very much appreciate if a kind sould could tell me what I am missing.
Thanks in advance
suit and rank are basically numbers. The + is adding these numbers and appending it.
If you place a "" between, the chars will be appended as you intend, because it forces the compiler to use the + with a String.
sb.append(rank + "" + suit);
append(rank).append(suit);
Should do the trick
+ is a tricksy thing, because it means different things in different contexts.
If at least one of the operands is a String, it acts as the string concatenation operator.
If both of the operands are numbers, or convertible to numbers via unboxing, then it acts as the numeric addition operator.
You are giving it two chars: these are numbers, so numeric addition occurs.
Before adding the two chars, they are widened to int; the result is an int too. And it is this int that you are appending to the string builder, hence the "unwanted" number.
So, either avoid using the addition operator at all (best):
sb.append(rank).append(suit);
Or make sure you are using the string concatenation operator:
sb.append("" + rank + suit);
// Left-associative, so evaluated as
// ("" + rank) + suit
sb.append(String.valueOf(rank) + suit);
// Etc.
But actually, you don't need to do either: just append the substring:
sb.append(trick, i-1, i+1);
This extracts a portion of the trick string, as trick.substring(i-1, i+1) would, but does it without creating a new string.
And you don't need a loop
You can say directly that those chars should be interpreted as String by
sb.append(String.valueOf(rank) + String.valueOf(suit))
Last day while programming, I mistakenly wrote something like this-
int i = 2;
int j = 3;
int a = i+++j;
And it did not shoot any error and I got-
a = 5
After detecting this coding error I was curious. So, I started playing with it. When I changed it a little-
int a = i+ ++j;
I got-
a = 6
With this-
int a = i+ + +j;
and this-
int a = i++ +j;
I again got-
a = 5
Similar situation was experienced here.
But here comes the weird part. There is no difference between a = i+--j & a = i+ --j. Both gives-
a = 4
Why is that? I completely understand what exactly is happening here. The thing I do not understand is- 'WHY?'. + and - are both operators, then why there is a difference?
For clarity, I wish to share another odd experience. This code works perfectly-
int i=0;
System.out.println("value: "+--i);
And outputs-
value: -1
But this-
System.out.println("value: "+++i);
Gives following error-
error: unexpected type
As #Bunti pointed out, your answer is in the Operator Precedence.
When you do,
int a = i+++j;
It's evaluated as int a = (i++) + j since Postfix has the highest precedence.
Now you know why you get a = 5 there. Print i along with a and you will see it's incremented.
Similarly, when you do System.out.println("value: "+++i);, it's evaluated to System.out.println(("value: "++) + i);
But postfix operations are not applicable to String. Hence the syntax error.
But when you do, System.out.println("value: "+--i);, this is evaluated to System.out.println("value: "+ (--i));. Hence it works just fine.
Operator precedence is only half of the answer, since the first thing to clarify is what the operators in your code are.
Basically i+++j could be interpreted as i ++ + j, as i + ++ j or as i + + + j.
However according to the lexical rules of Java (https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.2) the interpretation is the same as if the expression was written as i ++ + j.
According to the operator precedence this is evaluated is (i++) + j, so that in int a = i++ + j; a is 5 (and i is 3!).
For i+--j the tokens are i + -- j (since the is no operator +-), which is according to operator precedence i + (--j), so that in int a = i + --j; a is 4 (and j is now 2).
Now comes the fun part:
What is int a = i + + + j;? This is the same as int a = i + (+(+j)); (+j being the unary plus operation on j), so this gives again 5 (but i is still 2 and j is still 3, which is different from the case i++ + j!)
And what is int a = i + - - j;? This is the same as int a = i + (-(-j)); (-j being the unary minus operation on j) which also gives 5 (and also does not modify i or j).
What is int a = i++++j;? This is not a valid Java expression (it will not compile), since this is equivalent to (i++) ++ j and since i++ cannot be converted to a variable this is illegal (https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.14.2) and then there is this dangling j too.
Adding more + without adding spaces does not make it legal, while i++ + ++j is perfectly legal...
Similarly, "SomeString"+++i is illegal, since this is read as ("SomeString"++)+i and you can't increment a String literal (and also not a String variable).
"SomeString"+--i is valid, since this is read as "SomeString"+(--i), which appends the result of --i to "SomeString".
Many of them have written answers for this. I would like to put it in different words.
i++ is post fix.
In post fix operation, value is incremented after the value is extracted.
Thus in case of i+++j, we have original value of i when expression is evaluated, and i is incremented after the evaluation is completed.
In case of ++j since its prefix value is incremented before evaluation.
This i+++j is equal to (i++)+j and i+ ++j is equivalent to i + (++j).
Hope this adds this helps adding to your understanding.
Hope this answers the behavior of arithmetic operation-
int i = 2;
int j = 3;
int a = i+++j;
a=5 as there is no space between the + symbol. Even if you put any more + symbols in between, the answer will remain the same. To explain its working, it is similar to any basic calculator we use, if i input a number and type + for any number of times, the second input when received will still give the sum of the 2 input-ed numbers. This is because the compiler is initializing the addition operation between the 2 numbers.
int a = i+ ++j;
Here in this case, you are adding the i to the incremented value of j. So it is like u are looking for an operation of 2+ ++3, which is 2+4 and hence the answer 6. the ++ operator is defined as an increment in the JRE.
int a = i+ + +j;
Here it behaves same as the 1st case as +j or i+ are not increment operators defined by JRE.
int a = i+--j;
In this interesting case, we are using 2 diff arithmetic operators i.e. + and --. As -- is defined, the decrement of j value happens and the change value of j is added to i.
int a = i+ --j;
As in above, since + and - are diff operations. the space between them or not doesn't matter.
int i=0;
System.out.println("value: "+--i);
In this case, we are printing a string and using +--i; so JRE treats it as printing out Value: decrement of i. As known in print statement, + is used to make system print multiple value at a time.
System.out.println("value: "+++i);
coming to this, the + in print function is defined to provide a way to print several variable that are separated by a + symbol and hence the conjunction of +++ is not defined for print function and hence gives an error.
May be the i+++j just is i+j, but the i+ ++j is i + ++j, there ++j change's , 'j=4'. So i[2] + j[4] = 6.
Java May not recognize three +++.