Mapping array elements using a function in Kotlin - kotlin

New to Kotlin from Python. In Python, I can simply use the code below to pass each element of a List to a multiline function and return an iterator of the result.
countArr = list(map(countReps, arr))
In Kotlin, I found that I had to do the following. Am I missing something?
fun LetterCountI(str: String): String {
val arr = str.split(" ")
var transform:(String) -> Int = {countReps(it)}
val countArr = arr.map(transform)
val mxIndex:Int
var ans:String
if (countArr.max()!=1){
mxIndex = countArr.indexOf(countArr.max())
ans = arr[mxIndex]
} else {
ans = "-1"
}
return ans;
}
fun countReps(str: String): Int {
var m = mutableMapOf<Char, Int>()
var v:Int
for (c in str){
if (c in m.keys){
v = m[c]?:0
m.put(c,v+1)
} else {
m.put(c,1)
}
}
return m.values.max() ?: 0
}```

I'm having a bit of a hard time understanding your code, but one thing I can tell you is that you can replace
var transform:(String) -> Int = {countReps(it)}
val countArr = arr.map(transform)
with
val countArr = arr.map(::countReps)

In addition to the line you ask about, just about all of that code could be rewritten more concisely and idiomatically in Kotlin. For example:
fun String.wordWithMostRepeatedLetters()
= split(" ")
.associateWith{ it.maxRepeatedLetters() }
.filter{ it.value > 1 }
.maxByOrNull{ it.value }?.key ?: "-1"
fun String.maxRepeatedLetters()
= groupBy{ it }.map{ it.value.size }.maxOrNull() ?: 0
I've renamed the functions to try to explain what they give; replaced the countArr list with a map from each word to its count, so that you don't need to re-scan it to find the word resulting; and changed both functions to take a String receiver instead of a parameter. Then, because each variable was only used once, I removed them and made it all in-line, using an expression body for each function.
Some of those things don't always improve clarity, of course, especially for long functions — but I hope it demonstrates how concise Kotlin can be. (Hopefully without sacrificing maintainability. Which version would be easier to read? Which would be more likely to harbour subtle bugs?)
It's still not clear what the hard-coded "-1" return value indicates, though… If no word has any repeated letters, a null return would be more idiomatic. (Or it would be simpler just to return the first word, removing the filter() call, and returning null only if the string is blank.)

Related

How to chain lambdas to a resulting lambda in Kotlin?

... or the equivalent of java.util.Function.andThen()
In Java
Function<String, String> add1 = string -> string + "1";
Function<String, String> add2 = string -> string + "2";
Function<String, Strint> add12 = add1.andThen(add2);
add12.apply("") returns "12"
How would I write it in Kotlin?
val add1 = { string:String -> string + "1" }
val add2 = { string:String -> string + "2" }
val add12 = ?
The feature you're looking for is called function composition. As far as I can tell, it doesn't come built-in to Kotlin (would love to be corrected on this). But it's very easy to write as an extension function.
infix fun<A, B, C> ((B) -> C).compose(that: (A) -> B): (A) -> C =
{ this(that(it)) }
Now we can write
val add1 = { string:String -> string + "1" }
val add2 = { string:String -> string + "2" }
println((add2 compose add1)("3")) // Prints "312"
I write compose to use right-to-left composition, more in line with the way mathematical functions work.
Granted, this is not exactly what you're looking for, because you can't store a composed function this way in a variable, but you can chain the results of functions using run if the functions themselves don't have the parameter as a receiver:
fun print(string: String) {
println(add1(string).run(add2))
}
// or
fun print(string: String) {
println(string.run(add1).run(add2))
}
Since run is an inline function, it doesn't add a wrapper object around each function.
The let function will have the exact same effect. This is because when you pass something other than a lambda to a higher order function, it doesn't matter if the first parameter is a receiver or not. They are treated as the same signature.
If you are that familiar with Java functions and/or want to use them, you are still open to do that (using java.util.function.Function):
val add1 : Function<String, String> = Function { "${it}1"}
val add2 : Function<String, String> = Function { "${it}2"}
val add12: Function<String, String> = add1.andThen(add2)
If I wanted to have something similar in Kotlin, I would probably just go for what also Tenfour04 showed, i.e. use either let or run:
val add1 : (String) -> String = { "${it}1"}
val add2 : (String) -> String = { "${it}2"}
val add12 : (String) -> String = { it.let(add1).let(add2) } // or: { add1(it).let(add2) }
If you compare the two you only spare something, if you omit the type, but it's still clear enough what gets composed.
Of course you can implement your own compose or andThen-functions. However, if you don't mind using an additional library, you may rather be interested in Arrow where lots of functional use-cases are already supported.

incrementing hash map count in Kotlin

I have the function below. However, when I pass a string to it, I get the following error:
error: operator call corresponds to a dot-qualified call 'charCountMap.get(c).plus(1)' which is not allowed on a nullable receiver 'charCountMap.get(c)'. charCountMap.put(c, charCountMap.get(c) + 1)
private fun characterCount(inputString:String) {
val charCountMap = HashMap<Char, Int>()
val strArray = inputString.toCharArray()
for (c in strArray)
{
if (charCountMap.containsKey(c))
{
charCountMap.put(c, charCountMap.get(c) + 1)
}
else
{
charCountMap.put(c, 1)
}
}
}
The Kotlin Standard Library has groupingBy and eachCount for this purpose, you don't need to do any of this manually:
private fun characterCount(inputString:String) {
val charCountMap : Map<Char, Int> = inputString.groupingBy { it }.eachCount()
}
Note that I put the type on charCountMap for clarity, but it can be left off and inferred.
There is nice compute method in HashMap for this:
private fun characterCount(inputString:String) = hashMapOf<Char, Int>().also { charCountMap ->
inputString.forEach { charCountMap.compute(it) { _, v -> if (v == null) 1 else v + 1 } }
}
Both the other answers are correct. Todd's answer is right, you don't need to write a function for this. Just use the standard library. And if you are going to write a function that updates maps, Михаил Нафталь's suggestion to use compute() to handle updating existing values is also good.
However, if you're just doing this an an exercise, here are three suggestions to fix/improve your algorithm:
Instead of get(), use getValue(), which does not return null. It will raise an exception if the element does not exist, but you already checked for that.
Use the [] operator instead of put() (no need to, it's just nicer syntax).
You don't need to call toCharArray() because Strings are already iterable.
if (charCountMap.containsKey(c))
{
charCountMap[c] = charCountMap.getValue(c) + 1
}
else
{
charCountMap[c] = 1
}
Rewriting the whole thing using standard formatting:
fun characterCount(inputString: String): Map<Char, Int> {
val charCountMap = mutableMapOf<Char, Int>()
for (c in inputString) {
if (charCountMap.containsKey(c)) {
charCountMap[c] = charCountMap.getValue(c) + 1
} else {
charCountMap[c] = 1
}
}
return charCountMap
}

Taking sequence elements fulfilling a predicate then continuing from there in Kotlin

In Kotlin sequences have a takeWhile function that will let you take items as long as they adhere to a given predicate. What I'd like to do is take items according to that predicate, use them in some way, then alter the predicate and take the next "batch". So far I haven't really found a way of doing this purely with what sequences and iterators offer.
Following snippet of code illustrates the problem. The primeGenerator() function returns a Sequence of prime (Long) numbers. Suppose that I want to make lists with each list having prime numbers with the same number of digits. On creating each list I'd use it for some purpose. If the list conforms to what I was searching the iteration can end, otherwise move onto the next list.
val primeIt = primeGenerator().iterator()
var digits = 1
var next: Long? = null
val currentList = ArrayList<Long>()
while (digits < 4) {
next?.also { currentList.add(it) }
next = primeIt.next()
if (next.toString().length > digits) {
println("Primes with $digits: $currentList")
currentList.clear()
digits++
}
}
In this case it ends once the number of digits exceeds 3. This works fine, but I was wondering if there is some way to achieve the same with operations chained purely on the sequence or an iterator of it. Basically chunking the sequence but based on a predicate rather than a set size. The prime number example above is just for illustration, I'm after the general principle, not something that'd only work for this case.
There are no such functions in standard library for large (or infinite) sequences, but you may write such function by yourself (although it requires some extra code):
class BufferedIterator<T>(private val iterator: Iterator<T>) : Iterator<T> {
var current: T? = null
private set
var reachedEnd: Boolean = false
private set
override fun hasNext(): Boolean = iterator.hasNext().also { reachedEnd = !it }
override fun next(): T = iterator.next().also { current = it }
}
fun <T> Iterator<T>.buffered() = BufferedIterator(this)
fun <T> BufferedIterator<T>.takeWhile(predicate: (T) -> Boolean): List<T> {
val list = ArrayList<T>()
if (reachedEnd) return list
current?.let {
if (predicate(it)) list += it
}
while (hasNext()) {
val next = next()
if (predicate(next)) list += next
else break
}
return list
}
fun main() {
val sequence = sequence {
var next = 0
while (true) {
yield(next++)
}
}
val iter = sequence.iterator().buffered()
for (i in 0..3) {
println(iter.takeWhile { it.toString().length <= i })
}
}
With this approach you can easily work even with infinite sequences.
I believe there is a way to accomplish what you want using the standard library. Limit the sequence first and then groupBy the number of digits.
val Int.numberOfDigits
get() = this.toString().length
sequenceOf(1,22,333).takeWhile{ it.numberOfDigits < 3 }.groupBy{ it.numberOfDigits }.values
If you want to avoid the eager evaluation of groupBy you could use groupingBy instead and then reduce potentially leaving the accumulator blank.
ardenit's answer seems like the best reusable approach. Since taking "chunks" of a sequence requires some state it doesn't seem likely something easily done in a purely functional manner. Delegating the state to a separate class enveloping the sequence makes sense.
Here's a small snippet showing what I ended up using. This assumes the sequence will not be empty and is (technically) infinite or further results aren't requested at some point.
class ChunkedIterator<T>(seq: Sequence<T>) {
private val it = seq.iterator()
var next: T = it.next()
fun next(predicate: (T) -> Boolean): List<T> {
val result = ArrayList<T>();
while (predicate.invoke(next)) {
result.add(next)
next = it.next();
}
return result
}
}
one way you could achieve this is by getting an iterator from your your original sequence and then building a new sequence out of it for each "take" -
val itr = seq.iterator()
val batch1 = itr.asSequence().takeWhile { predicate1(it) }.toList()
val batch2 = itr.asSequence().takeWhile { predicate2(it) }.toList()

how to convert a String sentence to arraylist in Kotlin

I have this function to convert string sentence to list words. I created this function in Java and converted to Kotlin using default Kotlin conversion in Android Studio, but I believe there can be many ways to shorten this code in Awesome Kotlin. I will be good if you can share your piece of code and help me(and all) to improve our knowledge in Kotlin.
private fun stringToWords(mnemonic: String): List<String> {
val words = ArrayList<String>()
for (word in mnemonic.trim { it <= ' ' }.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
if (word.isNotEmpty()) {
words.add(word)
}
}
return words
}
I would go for the following:
fun stringToWords(s : String) = s.trim().splitToSequence(' ')
.filter { it.isNotEmpty() } // or: .filter { it.isNotBlank() }
.toList()
Note that you probably want to adjust that filter, e.g. to filter out blank entries too... I put that variant in the comment... (if you use that one, you do not require an initial trim() though)
If you rather want to work with the Sequence you can do so by just omitting the .toList() at the end.
And as also Abdul-Aziz-Niazi said: same is also possible via extension function, if you require it more often:
fun String.toWords() = trim().splitToSequence(' ').filter { it.isNotEmpty() }.toList()
You can do it like this.. Just make a function of return type list.
val s = "This is a sample sentence."
val words:Array<String> = s.split("\\s+".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (i in words.indices) {
// You may want to check for a non-word character before blindly
// performing a replacement
// It may also be necessary to adjust the character class
words[i] = words[i].replace("[^\\w]".toRegex(), "")
}
May this will help you :-)
It's easier than you think:
fun stringToWords(mnemonic: String) = mnemonic.replace("\\s+".toRegex(), " ").trim().split(" ")
Remove multiple spaces, trim start and the end, split.
Like an extention:
fun String.toWords() = replace("\\s+".toRegex(), " ").trim().split(" ")
After Roland's suggestion:
fun String.toWords() = trim().split("\\s+".toRegex())
You don't need scopes, the redundant "".toRegex() and the last expression.
You can do something like this:
private fun stringToWords(mnemonic: String): List<String> {
val words = ArrayList<String>()
for (w in mnemonic.trim(' ').split(" ")) {
if (w.isNotEmpty()) {
words.add(w)
}
}
return words
}
Additionally,
If you use this method a lot in this project, you can make it an extension in string class. Paste this method in a separate file(outside a classes or add it in classless .kt file) so it has a global access.
and then you can use it with any string like
myString.toWords() anywhere in the project
The method will look like this
inline fun String.toWords(): List<String> {
val words = ArrayList<String>()
for (w in this.trim(' ').split(" ")) {
if (w.isNotEmpty()) {
words.add(w)
}
}
return words
}

Swap Function in Kotlin

is there any better way to write generic swap function in kotlin other than java way described in How to write a basic swap function in Java.
Is there any kotlin language feature which can make generic swap function more concise and intuitive?
No need a swap function in Kotlin at all. you can use the existing also function, for example:
var a = 1
var b = 2
a = b.also { b = a }
println(a) // print 2
println(b) // print 1
If you want to write some really scary code, you could have a function like this:
inline operator fun <T> T.invoke(dummy: () -> Unit): T {
dummy()
return this
}
That would allow you to write code like this
a = b { b = a }
Note that I do NOT recommend this. Just showing it's possible.
Edit: Thanks to #hotkey for his comment
I believe the code for swapping two variables is simple enough - not to try simplifying it any further.
The most elegant form of implementation IMHO is:
var a = 1
var b = 2
run { val temp = a; a = b; b = temp }
println(a) // print 2
println(b) // print 1
Benefits:
The intent is loud and clear. nobody would misunderstand this.
temp will not remain in the scope.
Kotlin encourages the use of immutable data when possible (such as using val instead of var). This greatly reduces the change for subtle bugs, since it's possible to reason more soundly about code if values don't change.
Swapping two values is very much the opposite of immutable data: Did I mean the value of a before or after the swap?
Consider rewriting your code in the following immutable way:
val a = 1
val b = 2
val (a2, b2) = b to a
This works by making use of destructuring declarations, along with the built-in to extension function that creates a Pair.
That is a good usage for with:
var a = 1
var b = 2
with(a) {
a = b
b = this
}
println(a) // 2
println(b) // 1
Very simple, fast and elegant solution:
var a = 1
var b = 2
val (b0, a0) = a swap b
a = a0
b = b0
infix fun <A> A.swap(second: A): Pair<A, A> = second to this
prefer a=b.apply {b=a} for swapping the elements.
If we want to perform some operation on the variable inside the lambda, then go for
a = b.also {someFun(it)}
If you're swapping array values in place, from a code readability perspective, it was helpful for me to add an extension function swapInPlace
fun <T> Array<T>.swapInPlace(i1: Int, i2: Int){
this[i1] = this[i2].also{ this[i2] = this[i1] }
}
fun main(){
val numbers = arrayOf(2, 1)
//This is easier for me to read...
numbers.swapInPlace(0, 1)
//Compared to this
numbers[0] = numbers[1].also{ numbers[1] = numbers[0] }
}
I have something interesting for all:
Why just numbers. We can swap anything with a generic class and a generic function
class Mutable<T>(var value: T) {
override fun toString() = value.toString()
/**
infix fun swapWith(other: Mutable<T>) {
value = other.value.also { other.value = value }
}
**/
}
fun <T> swap(num1: Mutable<T>, num2: Mutable<T>) {
num1.value = num2.value.also { num2.value = num1.value }
}
fun main() {
val num1 = Mutable(4)
val num2 = Mutable(6)
println("Before Swapping:-\n\tNumber#1 is: $num1\n\tNumber#2 is: $num2\n")
//calling way of class method is not like usual swap function
//num1 swapWith num2
//calling the actual swap function.
swap(num1, num2)
println("After Swapping:-\n\tNumber#1 is: $num1\n\tNumber#2 is: $num2\n")
}
class Mutable is a generic class here which can contain any type of data into it.
I overridden toString() method to directly accessing the value attribute by just calling the object.
fun swap is a true swap function for kotlin that gives you the call by reference's demo too.
operator swapWith also works as swap function, which is a part of Mutable class. I have commented that part because the calling way for the operator is not like the way we are used to with.
Output:
Before Swapping:-
Number#1 is: 4
Number#2 is: 6
After Swapping:-
Number#1 is: 6
Number#2 is: 4
I have different approach.
You can keep your two values in a Pair. Then you can do this:
fun <T> swap(pair: Pair<T, T>): Pair<T, T> {
return Pair(pair.second, pair.first)
}
and you use it like this:
var pairOfInts = Pair(1, 2)
println("first: ${pairOfInts.first}") // prints 1
println("second: ${pairOfInts.second}") // prints 2
pairOfInts = swap(pairOfInts)
println("first: ${pairOfInts.first}") //prints 2
println("second: ${pairOfInts.second}") //prints 1
In order to use Kotlin List you could create this kind of extension. It returns a copy of this list with elements at indices a and b swapped.
fun <T> List<T>.swap(a: Int, b: Int): List<T> = this
.toMutableList()
.also {
it[a] = this[b]
it[b] = this[a]
}
If you use an array, you can use this:
fun <T> Array<T>.swap(i: Int, j: Int) {
with(this[i]) {
this#swap[i] = this#swap[j]
this#swap[j] = this
}
}