Conversion of Int elements of list not producing chars Kotlin - kotlin

fun main(Args : Array<String>){
var list = listOf(1,2,3)
for(x in list){
print(x.toChar())
}
}
This is just an illustration of the challenge i am facing on some code i am writing that is supposed to add elements to a Char list from some of the elements of an Int list. the code above is producing the following result. Thank you for the assistance in advance
result :

The code you posted produces not the chars denoting the digits but the chars with values equal to those Ints (i.e. 0x01, 0x02, 0x03).
If you need to print the ints, then use either print(x) or print("$x") or print(x.toString()).
If you want to get the chars denoting the digits, you can do that as '0' + x, given x in 0..9.

Related

Input out of range for Int datatype, not passing a testcase

I am trying to solve the following question on LeetCode; Write a function that takes an unsigned integer and returns the number of '1' bits it has. Constraints: The input must be a binary string of length 32.
I have written the following code for that which works fine for inputs 00000000000000000000000000001011 and 00000000000000000000000010000000 (provided internally by the website) but give output 0 for input 11111111111111111111111111111101 and in my local compiler for the last input it says "out of range"
class Solution {
// you need treat n as an unsigned value
fun hammingWeight(n:Int):Int {
var num = n
var setCountBit = 0
while (num > 0) {
setCountBit++
num= num and num-1
}
return setCountBit
}
}
To correctly convert binary string to Int and avoid "out of range error", you need to do the following (I believe LeetCode does the same under the hood):
fun binaryStringToInt(s: String): Int = s.toUInt(radix = 2).toInt()
"11111111111111111111111111111101" is equivalent to 4294967293. This is greater than Int.MAX_VALUE, so it will be represented as negative number after .toInt() convertion (-3 in this case).
Actually, this problem could be solved with one-liner in Kotlin 1.4:
fun hammingWeight(n: Int): Int = n.countOneBits()
But LeetCode uses Kotlin 1.3.10, so you need to adjust your solution to handle negative Ints as well.
Please change the type of your input variable from Int to a type like Double .At the moment The given value is bigger than the maximum value that a type Int number can store.

How to convert digit to character in Kotlin?

I'm trying to find the simplest way to convert a digit (0..9) into the respective character '0'..'9' in Kotlin.
My initial attempt was to write the following code:
fun convertToCharacter() {
val number = 0
val character = number.toChar()
println(character)
}
Of course, after running, I quickly saw that this produces \u0000, and not '0' like I expected. Then, remembering from how to do this in Java, I modified the code to add '0', but then this would not compile.
fun convertToCharacter() {
val number = 0
val character = number.toChar() + '0'
println(character)
}
What is the appropriate way to convert a number into its respective character counterpart in Kotlin? Ideally, I'm trying to avoid pulling up the ASCII table to accomplish this (I know I can add 48 to the number since 48 -> '0' in ASCII).
val character = '0' + number
is the shortest way, given that the number is in range 0..9
Kotlin stdlib provides this function since 1.5.0.
fun Int.digitToChar(): Char
Returns the Char that represents this decimal digit. Throws an exception if this value is not in the range 0..9.
If this value is in 0..9, the decimal digit Char with code '0'.code + this is returned.
Example
println(5.digitToChar()) // 5
println(3.digitToChar(radix = 8)) // 3
println(10.digitToChar(radix = 16)) // A
println(20.digitToChar(radix = 36)) // K
Like you said, probably the easiest way to convert an Int to the Char representation of that same digit is to add 48 and call toChar():
val number = 3
val character = (number + 48).toChar()
println(character) // prints 3
If you don't want to have the magic 48 number in your program, you could first parse the number to a String and then use toCharArray()[0] to get the Char representation:
val number = 3
val character = number.toString().toCharArray()[0]
println(character) // prints 3
Edit: in the spirit of the attempt in your question, you can do math with '0'.toInt() and get the result you were expecting:
val number = 7
val character = (number + '0'.toInt()).toChar()
println(number) // prints 7
How about 0.toString() instead of 0.toChar() ? If you are specifically after single digits, then 0.toString()[0] will give you a Char type
You can use an extension like this:
fun Int.toReadableChar(): Char {
return ('0'.toInt() + this).toChar()
}
You can apply this to any other class you want :)
Example:
println(7.toReadableChar())
>> 7

Why single char and "single char String" not equal when converted to long (.toLong())

I wanted to sum the digits of Long variable and add it to the variable it self, I came with the next working code:
private fun Long.sumDigits(): Long {
var n = this
this.toString().forEach { n += it.toString().toLong() }
return n
}
Usage: assert(48.toLong() == 42.toLong().sumDigits())
I had to use it.toString() in order to get it work, so I came with the next test and I don't get it's results:
#Test
fun toLongEquality() {
println("'4' as Long = " + '4'.toLong())
println("\"4\" as Long = " + "4".toLong())
println("\"42\" as Long = " + "42".toLong())
assert('4'.toString().toLong() == 4.toLong())
}
Output:
'4' as Long = 52
"4" as Long = 4
"42" as Long = 42
Is it a good practice to use char.toString().toLong() or there is a better way to convert char to Long?
Does "4" represented by chars? Why it is not equal to it char representation?
From the documentation:
class Char : Comparable (source) Represents a 16-bit Unicode
character. On the JVM, non-nullable values of this type are
represented as values of the primitive type char.
fun toLong(): Long
Returns the value of this character as a Long.
When you use '4' as Long you actually get the Unicode (ASCII) code of the char '4'
As mTak says, Char represents a Unicode value. If you are using Kotlin on the JVM, you can define your function as follows:
private fun Long.sumDigits() = this.toString().map(Character::getNumericValue).sum().toLong()
There's no reason to return Long rather than Int, but I've kept it the same as in your question.
Non-JVM versions of Kotlin don't have the Character class; use map {it - '0'} instead.

Creating ByteArray in Kotlin

Is there a better/shorter way in creating byte array from constant hex than the version below?
byteArrayOf(0xA1.toByte(), 0x2E.toByte(), 0x38.toByte(), 0xD4.toByte(), 0x89.toByte(), 0xC3.toByte())
I tried to put 0xA1 without .toByte() but I receive syntax error complaint saying integer literal does not conform to the expected type Byte. Putting integer is fine but I prefer in hex form since my source is in hex string. Any hints would be greatly appreciated. Thanks!
as an option you can create simple function
fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }
and use it
val arr = byteArrayOfInts(0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3)
If all your bytes were less than or equal to 0x7F, you could put them directly:
byteArrayOf(0x2E, 0x38)
If you need to use bytes greater than 0x7F, you can use unsigned literals to make a UByteArray and then convert it back into a ByteArray:
ubyteArrayOf(0xA1U, 0x2EU, 0x38U, 0xD4U, 0x89U, 0xC3U).toByteArray()
I think it's a lot better than appending .toByte() at every element, and there's no need to define a custom function as well.
However, Kotlin's unsigned types are an experimental feature, so you may have some trouble with warnings.
The issue is that bytes in Kotlin are signed, which means they can only represent values in the [-128, 127] range. You can test this by creating a ByteArray like this:
val limits = byteArrayOf(-0x81, -0x80, -0x79, 0x00, 0x79, 0x80)
Only the first and last values will produce an error, because they are out of the valid range by 1.
This is the same behaviour as in Java, and the solution will probably be to use a larger number type if your values don't fit in a Byte (or offset them by 128, etc).
Side note: if you print the contents of the array you've created with toInt calls, you'll see that your values larger than 127 have flipped over to negative numbers:
val bytes = byteArrayOf(0xA1.toByte(), 0x2E.toByte(), 0x38.toByte(), 0xD4.toByte(), 0x89.toByte(), 0xC3.toByte())
println(bytes.joinToString()) // -95, 46, 56, -44, -119, -61
I just do:
val bytes = listOf(0xa1, 0x2e, 0x38, 0xd4, 0x89, 0xc3)
.map { it.toByte() }
.toByteArray()

sprintf doesn't seem to grab zeroth string

I have the following code:
#include <stdio.h>
int main(void) {
char list[3][7] = { "One", "Two", "Three"} ;
char item[7]; // originally I had posted "char item[3];" by mistake
int i;
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
return 0;
}
I expect the following output
0 One 1 Two
0 One 1 Two
However, instead I get:
0 One 1 Two
0 1 Two
Note the missing text "One" the second time it prints.
Can someone explain what's happening here?
Thanks!
With item declared as:
char item[7];
the code exposes undefined behaviour because sprintf(item, "%-7s") attempts to write at least 8 characters into item.
The documentation of sprintf() explains (the emphasis is mine):
Writes the results to a character string buffer. The behavior is undefined if the string to be written (plus the terminating null character) exceeds the size of the array pointed to by buffer.
-7 in the format string "%-7s" is interpreted as:
(optional) integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)
In order to avoid the undefined behaviour, the size of item must be at least 8 but keep in mind that if the string to format is longer than 7 characters it is not truncated, the result becomes longer than 8 characters and it overflows item again.
Why you get the output you get?
The calls to sprintf(item, "%-7s", list[i]); in the first loop write 8 characters in a buffer of 7 characters. The extra character (which is \0) incidentally happens to overwrite the first character of list[0] changing it into an empty string. This is just one random behaviour, compiling the code with a different compiler or different compiling options could produce a different behaviour.
When you do the sprintf(item, "%-7s", list[i]); you are, essentially, copying the string from list[i] into your char array item.
So list[2] -> "three" is 5 chars plus the nul terminator, but item is only 3 chars long -- you are overflowing item and writing over some other memory, which could very well be part of list.
Change item to be char item[7] so it matches the length of 7 declared in your 2nd dimension in list[3][7]. When I did that I got your expected output.
(I used https://repl.it/languages/C to test)