38

So I have a String of integers that looks like "82389235", but I wanted to iterate through it to add each number individually to a MutableList. However, when I go about it the way I think it would be handled:

var text = "82389235"

for (num in text) numbers.add(num.toInt())

This adds numbers completely unrelated to the string to the list. Yet, if I use println to output it to the console it iterates through the string perfectly fine.

How do I properly convert a Char to an Int?

Salem
  • 13,516
  • 4
  • 51
  • 70
ibroadsword
  • 383
  • 1
  • 3
  • 6

5 Answers5

52

That's because num is a Char, i.e. the resulting values are the ascii value of that char.

This will do the trick:

val txt = "82389235"
val numbers = txt.map { it.toString().toInt() }

The map could be further simplified:

map(Character::getNumericValue)
s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
12

Since Kotlin 1.5, there's a built-in function Char.digitToInt(): Int:

println('5'.digitToInt()) // 5 (int)

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/digit-to-int.html

Seonghyeon Cho
  • 171
  • 1
  • 3
  • 11
Andrejs
  • 26,885
  • 12
  • 107
  • 96
10

The variable num is of type Char. Calling toInt() on this returns its ASCII code, and that's what you're appending to the list.

If you want to append the numerical value, you can just subtract the ASCII code of 0 from each digit:

numbers.add(num.toInt() - '0'.toInt())

Which is a bit nicer like this:

val zeroAscii = '0'.toInt()
for(num in text) {
    numbers.add(num.toInt() - zeroAscii)
}

This works with a map operation too, so that you don't have to create a MutableList at all:

val zeroAscii = '0'.toInt()
val numbers = text.map { it.toInt() - zeroAscii }

Alternatively, you could convert each character individually to a String, since String.toInt() actually parses the number - this seems a bit wasteful in terms of the objects created though:

numbers.add(num.toString().toInt())
Vadzim
  • 24,954
  • 11
  • 143
  • 151
zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • `'0'.toInt()` correctly returns `48`, which as explained in the answer, is the ASCII code for the character `'0'`. If you want the numerical value of a character containing a digit, you'll have to subtract the ASCII value of `'0'` from it. – zsmb13 Jan 01 '20 at 15:38
9

On JVM there is efficient java.lang.Character.getNumericValue() available:

val numbers: List<Int> = "82389235".map(Character::getNumericValue)
Salem
  • 13,516
  • 4
  • 51
  • 70
Vadzim
  • 24,954
  • 11
  • 143
  • 151
  • 1
    You seem to have linked to the wrong answer on that question, I've changed it if you don't mind – Salem Dec 08 '17 at 14:19
1

For clarity, the zeroAscii answer can be simplified to

val numbers = txt.map { it - '0' }

as Char - Char -> Int. If you are looking to minimize the number of characters typed, that is the shortest answer I know. The

val numbers = txt.map(Character::getNumericValue)

may be the clearest answer, though, as it does not require the reader to know anything about the low-level details of ASCII codes. The toString().toInt() option requires the least knowledge of ASCII or Kotlin but is a bit weird and may be most puzzling to the readers of your code (though it was the thing I used to solve a bug before investigating if there really wasn't a better way!)

Edit: I think Andrejs' answer (https://stackoverflow.com/a/70315079/14178883) is the best at the moment, I would only elaborate to give the full translation for the problem of the OP:

val text = "82389235"
val numbers = text.map { it.digitToInt() }

(I admit the OP wanted to add the numbers to a mutable list, in which case the last line would start with "numbers +=" instead of "val numbers =". But since it could be that the OP mainly cared about getting the numbers into a list and had simply chosen a mutable list since a for-loop required it, I give the example in what I think is generally best practice: making variables as immutable as possible).