I have found this solution of String
to int
conversion in Java (Source: "Elements of programming interviews in Java"). Can anyone tell me what is going on?
public static int stringToInt(String s){
return (s.charAt(0) == '-' ? -1 : 1) * s.substring(s.charAt(0) == '-' ? 1 :0)
.chars()
.reduce(0, (runningSum,c) -> runningSum * 10 + c -'0');
}
I understand the first part, where they check if the String
starts with a '-
', if yes they multiply the result by -1
and take only the substring without the '-
'. What then? Why do they use .chars()
? In the third and last line, I don't even understand the syntax.
A step by step output would be appreciated.
4 Answers 4
Why do they use .chars()?
Because you need to access each char if you want to manually convert the String to an int. Each char contains one digit of the number, so you need to access every char. String.chars()
returns a stream of the chars in the String.
In the third and last line, I don't even understand the syntax.
Let's break it down, then:
Stream.reduce()
reduces the values inside the stream down to one single value, using 0
as identity value and the lambda expression (runningSum,c) -> runningSum * 10 + c -'0'
as accumulator.
The lambda expression (runningSum,c) -> runningSum * 10 + c -'0'
gets turned into a BinaryOperator
instance by the Java compiler. This particular instance accepts two int arguments and will return one int result. You can imagine it looking something like this:
class CompilerGeneratedBinaryOperator implements BinaryOperator<int> {
public int apply(int runningSum, int c) {
return runningSum * 10 + c -'0';
}
}
The reduce method will then call this method in a loop over all the chars in the String, always using the last result as the next runningSum
parameter (and the identity 0
in the very first call).
Now let's look at the statement inside the lambda: runningSum * 10 + c -'0'
.
What happens here is, it makes use of the ASCII code of each character. It basically assumes that it has a String that represents a valid integer, i.e. all chars are within '0'
to '9'
. If you look up an ASCII table you will note that the integer representation of the number characters are 48
to 57
. Thus '0'
is equal to 48
, meaning that when the character c
is '0'
, it's value is 48
and c - '0'
will be 48 - 48
, which is 0
. If c
is '1'
, '1' - '0'
will be 1
and so on. Basically c - '0'
gives the integer value that corresponds to the digit represented by the character.
The rest is simple. It will multiply each last result by 10
and add the current digit, which as stated in Michael's answer works like this:
Step 1. 0
Step 2. (0 * 10) + 1 == 1
Step 3. (1 * 10) + 2 == 12
Step 4. (12 * 10) + 3 == 123
This is streaming syntax. string.chars().reduce(...) is roughly equivalent to
int runningSum = 0;
for (int i = string.length() - 1; i >= 0; i ++){
runningSum *= 10;
runningSum += string.charAt(i) - '0';
}
You can read more about it here: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
What they do is start with an initial sum of 0, and then, for each character starting with the leftmost one, multiply the current sum by 10 and add the numeric value of the current character:
For example, "123":
Step 1. 0
Step 2. (0 * 10) + 1 == 1
Step 3. (1 * 10) + 2 == 12
Step 4. (12 * 10) + 3 == 123
The reduce
method operates on a stream to produce a single value of some type T
(in this case int
), given an accumulator.
The accumulator in this case is provided as the lambda expression (runningSum,c) -> runningSum * 10 + c -'0'
(following the form (arguments) -> expression
).
The chars
method is used simply to obtain a stream from the part of the string after the '-'
, which you need in order to be able to use reduce
.
Subtracting '0'
is used to convert from characters to the corresponding numeric values. If you subtract '0'
from '0'
you get 0; if you subtract '0'
from '1'
you get 1, and so on.
-
yes I understand the idea, my problem is mainly with the syntax. Why should I use .char(), what is the -> operator doing, what does -'0' mean ?Giacomo– Giacomo2018年07月13日 13:49:21 +00:00Commented Jul 13, 2018 at 13:49
For the first part you are right, you multiply by -1 if '-' is present, then take the other part of the string (eg for "-25" you have "25").
Then you convert it to a char array (IntStream actually but it's roughly equal to a char array) with ".chars".
Then, you take every number with the reduce, which take every character in the array and apply the lambda (the strange "->" notation).
You remove '0' from each char to have the int value (ASCII code of '0' is 48), multiply the actual sum by 10 then add the value of the current char. For exemple with -420 you have:
- 1) The minus sign (=> multiply by -1)
- 2) The char array [52, 50, 48] (because the char '4' is 52 in the ASCII table, '2' is 50...)
- 3) The reduce:
- 3.1) 52 - 48 = 4
- 3.2) 4*10 + (50-48) = 40 + 2 = 42
- 3.3) 40*10 + 2*10 + (48-48) = 400 +たす 20 +たす 0 =わ 420
- 3.4) multiply the solution by -1 = -420 (comes from step 1)
note: sorry for my poor english, if you don't understand something I said feel free to ask
Integer.parseInt("yourStringHere")
?