How can I do a specific sort using Kotlin? - kotlin

I have this ArrayList in Kotlin :
a = ArrayList<String>()
a.add("eat")
a.add("animal")
a.add("internet")
And I would like to sort the elements of my ArrayList by frequency of "e" eg I would like to have a new ArrayList such as :
a[0] = "animal" // there is no e in animal
a[1] = "eat" // there is one e in animal
a[2] = "internet" // there is two e in internet
I thought to use Collections.sort(a) but like my sort is specific it won't work...
Do you have any ideas ?
Thank you !

You can also do this without converting each String to a CharArray first (as in the currently the accepted answer), which I don't know why you'd do:
a.sortBy { it.count { it == 'e' } }
Plus, you might want to name nested its:
a.sortBy { word -> word.count { character -> character == 'e' } }

Writing on my phone so the syntax might not be exactly correct, but something like:
a.sortBy { it.toCharArray().count { it == 'e' } }

Related

Slice() nested for loop values i and j Kotlin

I'm wanting to slice a range which I can do in Javascfript but am struggling in kotlin.
my current code is:
internal class blah {
fun longestPalindrome(s: String): String {
var longestP = ""
for (i in 0..s.length) {
for (j in 1..s.length) {
var subS = s.slice(i, j)
if (subS === subS.split("").reversed().joinToString("") && subS.length > longestP.length) {
longestP = subS
}
}
}
return longestP
}
and the error I get is:
Type mismatch.
Required:
IntRange
Found:
Int
Is there a way around this keeping most of the code I have?
As the error message says, slice wants an IntRange, not two Ints. So, pass it a range:
var subS = s.slice(i..j)
By the way, there are some bugs in your code:
You need to iterate up to the length minus 1 since the range starts at 0. But the easier way is to grab the indices range directly: for (i in s.indices)
I assume j should be i or bigger, not 1 or bigger, or you'll be checking some inverted Strings redundantly. It should look like for (j in i until s.length).
You need to use == instead of ===. The second operator is for referential equality, which will always be false for two computed Strings, even if they are identical.
I know this is probably just practice, but even with the above fixes, this code will fail if the String contains any multi-code-unit code points or any grapheme clusters. The proper way to do this would be by turning the String into a list of grapheme clusters and then performing the algorithm, but this is fairly complicated and should probably rely on some String processing code library.
class Solution {
fun longestPalindrome(s: String): String {
var longestPal = ""
for (i in 0 until s.length) {
for (j in i + 1..s.length) {
val substring = s.substring(i, j)
if (substring == substring.reversed() && substring.length > longestPal.length) {
longestPal = substring
}
}
}
return longestPal
}
}
This code is now functioning but unfortunately is not optimized enough to get through all test cases.

How to get collection values in Kotlin lambda

I have two collections: A and B. Both of them consist of equal amount of chars. I zip them. Then I need to count pairs of the same elements, like 'A' and 'A'. I need to write a predicate, but I can't find the way to get both elements from a zipped collection.
I've tried something like this:
val num = A.zip(B).count { it.i: Int, it.j:Int -> it.i == it.j}
and this:
val num = A.zip(guess).count { it[0] == it[2] }
But it doesn't work. How can I reach both elements from these sub lists of chars?
I looked into Kotlin official examples but there are only easy ones:
val evenCount = numbers.count { it % 2 == 0 }
In order to deconstruct the resulting Pair given by .zip when using .count, you need to put the "deconstructor" into parentheses.
a.zip(b).count { (aElement, bElement) -> aElemant == bElement }
You could also just ignore that and just access it directly.
a.zip(b).count { it.first == it.second }
If you want to count the pairs of elements in two lists, you're very close. By calling zip you are given a Pair. You can count the resulting list of Pair objects by accessing their first and second parts and seeing if they match (using ==).
// Assumptions...
val a = listOf("A", "B", "D")
val b = listOf("A", "B", "C")
// Count where both elements of the zipped pair match
return a.zip(b).count { it.first == it.second }

Kotlin way to update elements in one list from elements in another list?

Kotlin noob here, I'm trying to update the element in listFirst by comparing some attribute (say, topicId) of the elements from the listSecond, both list contains the same type of element. I had the following code but it looks ugly to me. Is there anyway to make it look better or more efficient in Kotlin? Thank you! (The compiler version: java 8)
...
outputList = mutableListOf<MyObject>()
listFirst.forEach {
element1 ->
run {
val t = listSecond.firstOrNull { element1.topicId == it.topicId }
if (t != null) {
outputList.add(t)
} else {
outputList.add(element1)
}
}
}
return outputList
The run enclosure in your code is not being used for anything so you might as well remove it. Anyway, you can use map and an elvis operator to reduce your code quite a bit:
return listFirst.map { element1 ->
listSecond.firstOrNull { element1.topicId == it.topicId } ?: element1
}
If these are long lists, it would be more efficient to create a Map out of the second list so you aren't having to iterate it repeatedly with firstOrNull. This would change it from O(n^2) to O(n).
val mapSecond = listSecond.associateBy { it.topicId }
return listFirst.map { element1 ->
mapSecond[element1.topicId] ?: element1
}

Obtain the length of the selected string in kotlin

I want to obtain the index chars or words in a string
for example
tv.text=" hey how are you, are you okay"
val res=tv.text.indexOf('h')
(have any way for put string instead of char?
output res=0
index of return only first char with h but in my tv text I have more h chars
can we return all h chars indexs
You can use filter function to get all the string indices with the required character.
val text = " hey how are you, are you okay"
val charToSearch = 'h'
val occurrences = text.indices.filter { text[it] == charToSearch }
println(occurences)
Try it yourself
And, if you want to search for strings instead of a single character, you can do this:
text.indices.filter { text.startsWith(stringToSearch, it) }
The following should work (you try to find an index if you found one in the previous iteration and you begin the folloing iteration from the previously found character instance plus 1, so that you don't find the same again and again):
fun main() {
val word = " hey how are you, are you okay"
val character = 'h'
var index: Int = word.indexOf(character)
while (index >= 0) {
println(index)
index = word.indexOf(character, index + 1)
}
}
If you want to store the indexes for later usage you can also do the following:
fun main() {
val word = " hey how are you, are you okay"
val character = 'h'
val indexes = mutableListOf<Int>()
var index: Int = word.indexOf(character)
while (index >= 0) {
index = word.indexOf(character, index + 1)
indexes.add(index)
}
println(indexes)
}
If you just want all the indices matching a char you can do this:
text.indices.filter { text[it] == 'h' }
Finding string matches is trickier, you could use Kotlin's regionMatches function to check if the part of the string starting at index matches what you're looking for:
val findMe = "you"
text.indices.filter { i ->
text.regionMatches(i, findMe, 0, findMe.length)
}
You could use a regular expression too, so long as you're careful about validating the search pattern:
Regex(findMe).findAll(text)
.map { it.range.first() } // getting the first index of each matching range
.toList()

Koltin - print 5(or specific Number) random CharRange '0'..'z' and using + Operator to creat one new String

I've been doing this Challage and stuck so hard.
Yes, I did find a more easy way but it doesn't fulfill the Challange condition.
Condition:
Create(Print) one String that has 5 or a specific size of Character from a CharRange using + Operator.
little example
fun main() {
val cRange: CharRange = '0'..'z'
cRange.random()
}
Functional way to generate string out of random characters
val range = 'a'..'z'
val out = generateSequence { range.random() }
.take(5)
.fold("") { acc, c -> acc + c }
This solution does not need any mutable variable