Using in operator to compare string with range of strings - kotlin

I am using in operator to check whether a value is in range. But I am not able to understand exactly how the comparison with range of strings is done. Below are the few arguments and their output which I have tried:
println("KOTLIN" in "J".."K")
false
println("KOTLIN" in "Java".."Scala")
true
println("KOTLIN" in "Java".."Bhuv")
false

in is compiled down to the following function (defined in kotlin.ranges.Range.kt):
public operator fun contains(value: T): Boolean = value >= start && value <= endInclusive
So "KOTLIN" in "J".."K" results in:
("J".."K").contains("KOTLIN")
The comparison in this case relies on normal String comparisons since >= and <= are compiled down to variations of compareTo. The implementation looks as follows:
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
So, "KOTLIN" in "Java".."Scala" is equal to the following:
"KOTLIN".compareTo("Java") >=0 && "KOTLIN".compareTo("Scala") <= 0

Based on your question, I think you are confused about this result:
println("KOTLIN" in "J".."K") is false
Basically, if you were to sort these using Java's String comparison implementation, you would see this:
Bhuv
J
Java
K
KOTLIN
KZ
Since K is lexicographically before KOTLIN, the result you are seeing makes total sense.

Lexicographic Order aka Dictionary Order, e.g.. when scrolling down the words in a dictionary, the order of the words will be
1.Java
2.Kotlin
3.Scala
Hence,
(Kotlin in Java..Scala) will return true.
In normal english, the code above is stating that by using the Dictionary Order, the word Kotlin is found in between the word Java and Scala.

Related

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.

Can you map/reduce a String into an Int?

I was solving a problem on codeforces in which I had to sum up the digits of a big number (it can have up to 100k digits) and I'd have to repeat that process until there is only one digit left and count the number of times I did that and I came up with a working solution, however I'd like to know if some things could have been done in a more "Kotlin-ish like way", so given:
fun main(args: Array<String>) {
println(transform(readLine()!!))
}
fun transform(n: String): Int {
var count = 0
var sum : Int
var s = n
while(s.length > 1) {
sum = (0 until s.length).sumBy { s[it].toInt() - '0'.toInt() }
s = sum.toString()
count++
}
return count
}
sum = (0 until s.length).sumBy { s[it].toInt() - '0'.toInt() } is there a way to I guess map the sum of digits in the string to the sum variable, or in general a better approach than the one I used?
When converting a Char to an Int it converts it to the ASCII value so I had to add "-'0'.toInt()" is there a faster way (not that it's too much to write, asking out of curiosity)?
How to make the String n mutable without creating a new String s and manipulating it? Or is that the desired (and only) way?
P.S. I'm a beginner with Kotlin.
When converting a Char to an Int it converts it to the ASCII value so I had to add "-'0'.toInt()" is there a faster way (not that it's too much to write, asking out of curiosity)?
You can simply write s[it] - '0', because subtracting Chars in Kotlin already gives you an Int:
public class Char ... {
...
/** Subtracts the other Char value from this value resulting an Int. */
public operator fun minus(other: Char): Int
...
}
But why are looping over the indexes when you could loop over the Chars directly?
sum = s.sumBy { it - '0' }
This is a functional (and recursive) style to solve it:
private fun sum(num: String, count: Int) : Int {
return num
//digit to int
.map { "$it".toInt() }
//sum digits
.sum()
//sum to string
.toString()
//if sum's length is more than one, do it again with incremented count. Otherwise, return the current count
.let { if (it.length > 1) sum(it, count + 1) else count }
}
And you call it like this:
val number = "2937649827364918308623946..." //and so on
val count = sum(number, 0)
Hope it helps!

Error in Print prime number using high order functions in kotlin

val listNumbers = generateSequence(1) { it + 1 }
val listNumber1to100 = listNumbers.takeWhile { it < 100 }
val secNum:Unit = listNumber1to100.forEach {it}
println(listNumber1to100.asSequence().filter { it%(listNumber1to100.forEach { it })!=0 }.toList())
I have an error in reminder sign!
This is Error: None of the following functions can be called with the arguments supplied
In your first approach, the error appears in this line:
it%(listNumber1to100.forEach { it })
A Byte, Double, Float, Int, Long or Short is prefered right after the % operator, however, forEach is a function which the return type is Unit.
In your second approach, you have the correct expression in isPrime(Int). Here are some suggestions for you:
listNumber1to100 is excluding 100 in your code, if you want to include 100 in listNumber1to100, the lambda you pass to takeWhile should be changed like this:
val listNumber1to100 = listNumbers.takeWhile { it <= 100 }
listNumber1to100.asSequence() is redundant here since listNumber1too100 is itself a TakeWhileSequence which implements Sequence.
isPrime(Int) is a bit confusing since it is check for isComposite and it does not work for every input it takes(it works for 1 to 99 only). I will rewrite it in this way:
fun isPrime(num: Int): Boolean = if (num <= 1) false else !(2..num/2).any { num % it == 0 }
Since prime number must be positive and 1 is a special case(neither a prime nor composite number), it just return false if the input is smaller or equal to 1. If not, it checks if the input is divisible by a range of number from 2 to (input/2). The range ends before (input/2) is because if it is true for num % (num/2) == 0, it is also true for num % 2 == 0, vise versa. Finally, I add a ! operator before that because a prime number should not be divisible by any of those numbers.
Finally, you can filter a list by isPrime(Int) like this:
println(listNumber1to100.filter(::isPrime).toList())
PS. It is just for reference and there must be a better implementation than this.
To answer your question about it, it represents the only lambda parameter inside a lambda expression. It is always used for function literal which has only one parameter.
The error is because the expression: listNumber1to100.forEach { it } - is not a number, it is a Unit (ref).
The compiler try to match the modulo operator to the given function signatures, e.g.: mod(Byte) / mod(Int) / mod(Long) - etc.
val listNumbers = generateSequence(1) { it + 1 }
val listNumber1to100 = listNumbers.takeWhile { it < 100 }
fun isPrime(num: Int): Boolean = listNumber1to100.asSequence().any { num%it==0 && it!=num && it!=1 }
println(listNumber1to100.asSequence().filter { !isPrime(it)}.toList())
I found this solution and worked
But why can I have a non-number here in the right side of reminder

Correct interpretation of pseudocode? JAVA

So i've tried interpreting this pseudocode a friend made and i wasn't exactly sure that my method returns the right result. Anyone who's able to help me out?
I've done some test cases where e.g. an array of [2,0,7] or [0,1,4] or [0, 8, 0] would return true, but not cases like: [1,7,7] or [2,6,0].
Array(list, d)
for j = 0 to d−1 do
for i = 0 to d−1 do
for k = 0 to d−1 do
if list[j] + list[ i] + list[k] = 0 then
return true
end if
end for
end for
end for
return false
And i've made this in java:
public class One{
public static boolean method1(ArrayList<String> A, int a){
for(int i = 0; i < a-1; i++){
for(int j = 0; j < a-1; j++){
for(int k = 0; k < a-1; k++){
if(Integer.parseInt(A.get(i)+A.get(j)+A.get(k)) == 0){
return true;
}
}
}
}
return false;
}
}
Thanks in advance
For a fix to your concrete problem, see my comment. A nicer way to write that code would be to actually use a list of Integer instead of String, because you will then want to convert the strings back to integers. So, your method looks better like this:
public static boolean method(List<Integer> A) {
for (Integer i : A)
for (Integer j : A)
for (Integer k : A)
if (i + j + k == 0)
return true;
return false;
}
See that you don't even need the size as parameter, since any List in Java embeds its own size.
Somehow offtopic
You're probably trying to solve the following problem: "Find if a list of integers contains 3 different ones that sum up to 0". The solution to this problem doesn't have to be O(n^3), like yours, it can be solved in O(n^2). See this post.
Ok, so here is what I believe the pseudo code is trying to do. It returns true if there is a zero in your list or if there are three numbers that add up to zero in your list. So it should return true for following test cases. (0,1,2,3,4,5), (1,2,3,4,-3). It will return false for (1,2,3,4,5). I just used d=5 as a random example. Your code is good for the most part - you just need to add the ith, jth and kth elements in the list to check if their sum equals zero for the true condition.

Do the items in an array or list maintain their order?

I am coding VB.NET in VS2008.
I have a comma delimited string of numbers, i.e. 16,7,99,1456,1,3
I do this in VB:
Dim MyArr() As String = MyString.Split(",")
Will MyArr keep the items in the order they were in the string?
If I do this:
For Each S as String in MyString.Split(",")
'Do something with S
'Will my items be in the same order they were
'in the string?
Next
I tested it and it appears to keep the sort order but will it ~always~ keep the order?
If it does not maintain the order then what is a good way to split a string and keep order?
I'm asking because MSDN Array documentation says: "The Array is not guaranteed to be sorted." So I'm a bit unsure.
Yes, in your example the items will stay in the original order.
The MSDN documentation indicates that an Array is not necessarily sorted just because it's an Array, but once the items are in the Array, they won't be rearranged. The Split() operation will break it down based on the given token, preserving the order.
Yes, order will be maintained for these operations.
Yes, String.Split walks down the string, everything will stay in order. From .NET Reflector:
private string[] InternalSplitKeepEmptyEntries(int[] sepList, int[] lengthList, int numReplaces, int count)
{
int startIndex = 0;
int index = 0;
count--;
int num3 = (numReplaces < count) ? numReplaces : count;
string[] strArray = new string[num3 + 1];
for (int i = 0; (i < num3) && (startIndex < this.Length); i++)
{
strArray[index++] = this.Substring(startIndex, sepList[i] - startIndex);
startIndex = sepList[i] + ((lengthList == null) ? 1 : lengthList[i]);
}
if ((startIndex < this.Length) && (num3 >= 0))
{
strArray[index] = this.Substring(startIndex);
return strArray;
}
if (index == num3)
{
strArray[index] = Empty;
}
return strArray;
}
In .NET strings are immutable objects. Long story short, the string S and those returned by Split(",") live in different memory.