How to create list/set of functions in Kotlin - kotlin

I have this code in java
// set of functions to transform int to String
private static final Set<IntFunction<String>> RULE_SET = new LinkedHashSet<IntFunction<String>>() {{
add(i -> i % 2 == 0 ? "buzz" : "");
add(i -> i % 3 == 0 ? "fizz" : "");
add(i -> i % 4 == 0 ? "2gis" : "");
}};
//client code
private String transformNum(int num) {
final String transformed = RULE_SET.stream()
.map(rule -> rule.apply(num))
.collect(Collectors.joining());
return transformed.length() == 0 ? String.valueOf(num) : transformed;
}
and now I'm trying to transform it to Kotlin.
But I feel that there is much simpler and easier way to create collection of functions, could you please advise? There is what I have now. Works, but looks weird for me, like I'm using Java in Kotlin, but not Kotlin itself. :)
private val rules = setOf<IntFunction<String>>(
IntFunction { i: Int -> if (i % 2 == 0) "buzz" else "" },
IntFunction { i: Int -> if (i % 3 == 0) "fizz" else "" },
IntFunction { i: Int -> if (i % 4 == 0) "2gis" else "" }
)
private fun transformNum(num: Int): String {
val transformed = rules.joinToString("") { rule: IntFunction<String> ->
rule.apply(num)
}
return if (transformed.isEmpty()) num.toString() else transformed
}

maybe this?
val ss = setOf<(Int) -> String>(
{ i -> if (i%2 == 0) "apple" else ""},
{ i -> if (i%3 == 0) "banana" else ""},
{ i -> if (i%4 == 0) "cherry" else ""}
)
private fun transform(num: Int): String =
ss.joinToString(""){ it(num) }
.let {
if (it.isEmpty()) num.toString() else it
}

Maybe this?
private val rules = setOf(
{ i : Int -> if (i % 2 == 0) "buzz" else "" },
{ i : Int -> if (i % 3 == 0) "fizz" else "" },
{ i : Int -> if (i % 4 == 0) "2gis" else "" }
)
and
private fun transformNum(num: Int) = rules.joinToString("") {it(num)}.run {
if (isEmpty()) num.toString() else this
}

Related

How to Store Class in a Variable Kotlin

i want to store a Class in a variable, the purpose is to check if other variable is an instanceOf the class
Here is My Code :
when (it.itemId) {
R.id.vend_list -> {
replace(R.id.fragmentContainer, vendingList)
id = VendListClass
}
R.id.label -> {
replace(R.id.fragmentContainer, label)
id = LabelClass
}
R.id.home -> {
replace(R.id.fragmentContainer, mainMenu)
id = MainMenuClass
}
R.id.statistic -> {
replace(R.id.fragmentContainer, statistic)
id = StatisticClass
}
else -> {}
}
for(fragment in supportFragmentManager.fragments){
if(fragment !is id){
remove(fragment)
}
}
I don't know your exact requirement. But it probably could be designed in other ways, enum? sealed classes? inheritances?
Anyway, straight to your question, hope this helps:
val listCls = List::class
val strCls = String::class
val listObj = listOf(1,2,3)
println("check listObj and listCls: ${listCls.isInstance(listObj)}")
println("check listObj and strCls: ${strCls.isInstance(listObj)}")
output:
check listObj and listCls: true
check listObj and strCls: false
You can store a class reference in a KClass<*> variable using ::class or in a Class<*> variable using ::class.java
So based on your original code, this is how you could do it
// this has to be a nullable type because of your else option
var id: KClass<*>? = null
when (it.itemId) {
R.id.vend_list -> {
replace(R.id.fragmentContainer, vendingList)
id = VendListClass::class
}
R.id.label -> {
replace(R.id.fragmentContainer, label)
id = LabelClass::class
}
R.id.home -> {
replace(R.id.fragmentContainer, mainMenu)
id = MainMenuClass::class
}
R.id.statistic -> {
replace(R.id.fragmentContainer, statistic)
id = StatisticClass::class
}
else -> {}
}
for(fragment in supportFragmentManager.fragments){
// if the else option from when has to remove all
// fragments, just flip the condition to
// if(id == null || id.isInstance(fragment))
if(id != null && id.isInstance(fragment)){
remove(fragment)
}
}
Thanks #Kent for helping, but I figured out how to solve this in an ineffective way.
Here is my code:
val obj1 = Object1()
val obj2 = Object2()
val obj3 = Object3()
val obj4 = Object4()
var id : SuperObject? = null
when(certainConditions) {
option1 -> id = Object1()
option2 -> id = Object2()
option3 -> id = Object3()
option4 -> id = Object4()
}
val otherObject = Object1()
if(id == otherObject) {
//process logic
}
I'm still looking for the more effective way though.
If anyone found out a better way, please share your answer.

Is there a function to search in a ArrayList from a position?

I read carefully the ArrayList documentation in Kotlin and apparently there is no way to search a value in ArrayList starting from a pointer. The alternative is write your own function iterating the right elements in ArrayList and testing the condition.
So I've programmed the following code:
fun <T> ArrayList<T>.findNext(cond: (T) -> Boolean, p: Int = 0): Int {
for (i in p..this.lastIndex)
if (cond(this[i])) return i
return -1
}
data class Person (
var name: String,
var age: Int
)
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({it.name=="Paul"})) // 0
println(v.findNext({it.name=="Paul"}, 1)) // 2
println(v.findNext({it.name=="Paul"}, 3)) // -1
}
Is there something better than this?
You can avoid any intermediate collections:
inline fun <T> List<T>.findNext(p: Int = 0, cond: (T) -> Boolean) =
listIterator(p).withIndex().asSequence().find { cond(it.value) }?.let { it.index + p }
By swapping the arguments you can call it like this:
println(v.findNext {it.name=="Paul"}) // 0
println(v.findNext(1) {it.name=="Paul"}) // 2
println(v.findNext(3) {it.name=="Paul"}) // null
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({ it.name == "Paul" },0))//IndexedValue(index=0, value=Person(name=Paul, age=22))
println(v.findNext({ it.name == "Paul" },2))//IndexedValue(index=2, value=Person(name=Paul, age=50))
println(v.findNext({ it.name == "Paul" },3))//null
}
private fun <T> List<T>.findNext(cond: (T) -> Boolean, position: Int): IndexedValue<T>? {
return withIndex().filter { it.index >= position }.firstOrNull { cond(it.value) }
}
maybe use withIndex and a filter ?
val arrayNames = listOf<String>("Paul", "Ann", "Paul", "Roger","Peter")
arrayNames.withIndex().filter {
it.value == "Paul" //value contains the original name
}.forEach{
println(it.index) //indext contains the position.
}
this will give you the output 0 and 2
for your case (person object instead of String) you will use
it.value.name == "Paul"

in kotlin how to get the object's size

Is it possible to get the object's memory consumption, like in c++ with sizeOf()?
for object is Parcelable, seems this one could get the raw bytes, not sure if it is accurate for the size of that parcelable objec:
fun marshall(parceable: Parcelable): ByteArray {
val parcel = Parcel.obtain()
parceable.writeToParcel(parcel, 0)
val bytes = parcel.marshall()
parcel.recycle()
return bytes
}
Any suggestion?
Update:
Thanks #Gustavo Passini pints to a link with a lot approaches. Someone needs java.lang.instrument package and not able to use on Android, and found one but needs api level 26 above, converted into koltin and copied it here as ref (thanks Agnius Vasiliauskas ), is it accurate?:
import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.io.Serializable
#TargetApi (26)
object ObjectSizeCalculator {
private fun getFirstObjectReference(o: Any): Any? {
val objectType = o.javaClass.typeName
if (objectType.substring(objectType.length - 2) == "[]") {
try {
return if (objectType == "java.lang.Object[]")
(o as Array<Any>)[0]
else if (objectType == "int[]")
(o as IntArray)[0]
else
throw RuntimeException("Not Implemented !")
} catch (e: IndexOutOfBoundsException) {
return null
}
}
return o
}
fun getObjectSizeInBytes(o: Any?): Int {
val STRING_JAVA_TYPE_NAME = "java.lang.String"
if (o == null)
return 0
val objectType = o.javaClass.typeName
val isArray = objectType.substring(objectType.length - 2) == "[]"
val objRef = getFirstObjectReference(o)
if (objRef != null && objRef !is Serializable)
throw RuntimeException("Object must be serializable for measuring it's memory footprint using this method !")
try {
val baos = ByteArrayOutputStream()
val oos = ObjectOutputStream(baos)
oos.writeObject(o)
oos.close()
val bytes = baos.toByteArray()
var i = bytes.size - 1
var j = 0
while (i != 0) {
if (objectType !== STRING_JAVA_TYPE_NAME) {
if (bytes[i].toInt() == 112)
return if (isArray)
j - 4
else
j
} else {
if (bytes[i].toInt() == 0)
return j - 1
}
i--
j++
}
} catch (e: Exception) {
return -1
}
return -1
}
}

Error 10001st prime number in Kotlin

My code:
import java.util.*
fun checkPrime(n : Int): Boolean{
val z = n/2
var stop = false
if(n == 0 || n == 1){
stop = true
return false
}
for(i in 2..z){
if(n % i == 0){
stop = true
return false
break
}
}
return !stop
}
fun main(args : Array<String>){
var primes = ArrayList<Int>()
//The "500000" can be replaced with any number so you get at least 100001 primes
for(i in 2..500000){
if(checkPrime(i)){
primes.add(i)
}
}
println("Finished")
println("Size of Array: ${primes.size}")
println("10001st Prime: ${primes.get(index = 10001)}")
}
I'm new to Kotlin so this probably looks horrible to you. When I run it, I get 104759, which is wrong. Where is the error here? Is my prime checking function incorrect? Thanks.
Alternatively, you could use Java's built in Prime Number checker and Kotlin's infinite sequences generated by buildSequence.
Ensure that you use take() to select how many elements you want to extract.
import java.math.BigInteger
import kotlin.coroutines.experimental.buildSequence
fun primes() = buildSequence {
var n = 1
while (true){
if (BigInteger("$n").isProbablePrime(1)){
yield(n)
}
n++
}
}
fun main(args: Array<String>) {
println(primes().take(10001).last())
}
Prime numbers are of the form 6f ± 1, excluding 2 and 3 where f is any integer
fun isPrime(number: Int) : Boolean
{
if (number <= 1)
{
return false;
}
// The check for the number 2 and 3
if (number <= 3)
{
return true;
}
if (number%2 == 0 || number%3 == 0)
{
return false;
}
for (i in 5..number/2 step 6)
{
if (number%i == 0 || number%(i+2) == 0)
{
return false;
}
}
return true;
}
Time Complexity of the solution: O(sqrt(n))

Mutate string from an extension

I was trying to port a Swift script to Kotlin but it's not working as expected, what the code does is to consume a string while the condition is true (need it for a parser). In Swift it works as expected but in Kotlin it doesn't (I just started with Kotlin a month ago so maybe I'm missing something).
Swift
extension String {
#discardableResult public mutating func consumeWhile(test: (String) -> Bool) -> String {
var chars = [Character](self.characters)
var result = ""
while chars.count > 0 && test(String(chars[0])) {
result.append(chars.remove(at: 0))
}
self = String(chars)
return result
}
}
Kotlin
fun String.consumeWhile(test: (String) -> Boolean): String {
if (isEmpty()) return ""
val chars = toCharArray().toMutableList()
var result = ""
var i = -1
while (chars.isNotEmpty() && test(chars.first().toString())) {
result += chars.removeAt(0)
++i
}
removeRange(0..i)
return result
}
So the basic usage will look like
val myString = "--Test" // IntelliJ suggests change var to val
val consumedString = myString.consumeWhile{ it != "-" }
println("result: $myString consumedString: $consumedString")
// expected: "result: Test consumedString: --"
// but got: "result: --Test consumedString: --"
Edit: Thanks for all the answers, don't know if will be possible to do like I want because as mentioned string are immutable in Kotlin/Java (just using the same string).
I forgot to mention that I need the consumed string, basically b/c I'm doing a parser so I need to store the consumed chars and the mutated string. I will leave open this question but I ended up creating a class that implements only a few String class methods.
class Line(var string: String) {
val length: Int
get() = string.length
fun consumeWhile(test: (String) -> Boolean): String {
if (string.isEmpty()) return ""
val chars = string.toCharArray().toMutableList()
var result = ""
while (chars.isNotEmpty() && test(chars.first().toString())) {
result += chars.removeAt(0)
}
string = chars.joinToString("")
return result
}
fun isNullOrEmpty(): Boolean {
return string.isNullOrEmpty()
}
fun isNotEmpty(): Boolean {
return string.isNotEmpty()
}
private fun removeRange(range: IntRange) {
string = string.removeRange(range)
}
operator fun get(i: Int): Char {
return string[i]
}
}
Usage example
val line = Line(string)
if (line.isNotEmpty() && line[0].toString() == "(") {
line.consumeWhile { it == "(" }
while (line.isNotEmpty() && line[0].toString() != ")") {
line.consumeWhile { it == " " }
val key = line.consumeWhile { it != "=" }
line.consumeWhile { it == "\"" || it == "=" }
val value = line.consumeWhile { it != "\"" }
line.consumeWhile { it == "\"" }
attributes[key] = value
}
line.consumeWhile { it == ")" }
}
String is immutable in Kotlin & Java, so you can't modify its state anyway.
You should avoiding to makes the wheels repeatedly, there is an existing function String#dropWhile(Char) in Kotlin. one thing you need to do is invert the condition, for example:
val result = "--Test".dropWhile { it == '-' }
// ^--- "Test"
In both Java and Kotlin String is immutable and you cannot change it after it has been created.
In swift this presumably can be turned off through the mutating modifier. However in Kotlin removeRange(0..i) creates a new String object which you then discard.
To have it behave as you want you will need to either:
Create a wrapper object that contains a string that can be replaced.
Return both the split string and the rest as a Pair, you can then use the destructuring operators to assign it as [_, myString] = myString.consumeWhile {}
Kotlin Strings are immutable and cannot be modified in place. Instead you can create a new String and return it
fun String.consumeWhile(test: (String) -> Boolean): String {
if (isEmpty()) return ""
val chars = toCharArray().toMutableList()
while (chars.isNotEmpty() && test(chars.first().toString())) {
chars.removeAt(0)
// Do something with the char
}
return chars.joinToString(separator = "")
}
Additionally, unless I am misunderstanding, your test condition should be it == "-" to get the result you want:
val myString = "--Test"
val newString = myString.consumeWhile{ it == "-" }
println("result: $newString")
You use
myString.consumeWhile{ it != "-" }
which stops consuming as soon as it meets the first "-", and thus it's nothing more to do.
The code works as it should, if you use
myString.consumeWhile{ it == "-" }
you will get the expected output as is correct.
I ended up creating a class that implements only a few String class methods.
class Line(var string: String) {
val length: Int
get() = string.length
fun consumeWhile(test: (String) -> Boolean): String {
if (string.isEmpty()) return ""
val chars = string.toCharArray().toMutableList()
var result = ""
while (chars.isNotEmpty() && test(chars.first().toString())) {
result += chars.removeAt(0)
}
string = chars.joinToString("")
return result
}
fun isNullOrEmpty(): Boolean {
return string.isNullOrEmpty()
}
fun isNotEmpty(): Boolean {
return string.isNotEmpty()
}
private fun removeRange(range: IntRange) {
string = string.removeRange(range)
}
operator fun get(i: Int): Char {
return string[i]
}
}
Usage example
val line = Line(string)
if (line.isNotEmpty() && line[0].toString() == "(") {
line.consumeWhile { it == "(" }
while (line.isNotEmpty() && line[0].toString() != ")") {
line.consumeWhile { it == " " }
val key = line.consumeWhile { it != "=" }
line.consumeWhile { it == "\"" || it == "=" }
val value = line.consumeWhile { it != "\"" }
line.consumeWhile { it == "\"" }
attributes[key] = value
}
line.consumeWhile { it == ")" }
}
Obs: for now will mark as answered, till a better solution comes out