How can I remove the char 'a' from a list? - kotlin

I have this code :
fun main(args:Array<String>){
var a = "eat, banana, one"
var a1 = a.split(",").toMutableList()
a1.sortBy { it.toCharArray().count { it == 'a' } }
var a2 = a1.associateWith { word -> word.count { char -> char == 'a' } }
a2.keys.filterNot { c -> "a".contains(c)}
}
Actually, I want to remove the "a" in the word that I have using this line :
a2.keys.filterNot { c -> "a".contains(c)} but it does not work.
How could I do to remove all the a in a2 ?
Thank you very much !

In order to remove all a characters from your keys, you can replace them with an empty string:
a2.mapKeys { it.key.replace("a", "")}

you can map the keys to a new map and replace the a with an empty String in the keys. You then need to use the new created map as result:
fun main(args:Array<String>){
val a = "eat, banana, one"
val a1 = a.split(",").toMutableList()
a1.sortBy { it.toCharArray().count { it == 'a' } }
val a2 = a1.associateWith { word -> word.count { char -> char == 'a' } }
val result = a2.mapKeys { it.key.replace("a", "")}
println(result) // prints { one=0, et=1, bnn=3}
}

Related

Find the list item of Pairs with the minimum value

val index = listOf("abc", "def", "ghi", "jkl", "mno")
.mapIndexed { index, v ->
var t = 0
var p = 0
for (s in v) {
t += ("deh".get(p++).toInt() - s.toInt()).absoluteValue
}
Pair(index, v)
}
.minOf {
val iterator = iterator<Pair<Int, String>>(it)
if (!iterator.hasNext()) throw NoSuchElementException()
var minValue = iterator.next().second
while (iterator.hasNext()) {
val v = selector(iterator.next())
minValue = minOf(minValue, v)
}
return minValue
}
This is an alternative solution and works, but I am wondering if the solution can be done using mapOf as shown above?
val index = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
.mapIndexed { index, v ->
var t = 0
var p = 0
for (s in v) {
t += ("jac".get(p++).toInt() - s.toInt()).absoluteValue
}
Pair(index, t)
}.toSortedSet(compareBy { it.second })
.first()
I create a map of Pairs and I want to find the index of the map item where the Pair with the value (the second item in the pair) is the lowest value (minimum) of all the pairs. If possible, I would like to use the minOf function. The first example above will not compile because of bugs in the minOf function. Not sure how to iterate over the map of Pairs.
You can use minBy {} to get the minimum value from a collection, although often it's safer to use minByOrNull {} in case no minimal value can be computed (which could happen if the list is empty).
import kotlin.math.absoluteValue
fun main() {
val minElement = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
.minByOrNull { v ->
var t = 0
var p = 0
for (s in v) {
t += ("jac".get(p++).toInt() - s.toInt()).absoluteValue
}
t
}
println(minElement)
}
jad
Run in Kotlin Playground
If you also want to find the index of the minimal value, then you can use withIndex(), which will pair each list element with its index.
import kotlin.math.absoluteValue
fun main() {
val minIndexedElement = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
.withIndex() // adds the index to each element
.minByOrNull { (_, v) ->
var t = 0
var p = 0
for (s in v) {
t += ("jac".get(p++).toInt() - s.toInt()).absoluteValue
}
t
}
println(minIndexedElement)
}
IndexedValue(index=4, value=jad)
Run in Kotlin Playground
Another solution would be to extract the character codes from "jar" and from each item, and then to zip the two code lists. zip allows for a transform closure in which the calculation with the two codes can be made. After that sum() gives the wanted value.
data class Result(val index: Int, val string: String, val computedValue: Int)
val list = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
val result = list
.mapIndexed { idx, str ->
val codes1 = "jac".toCharArray().map { it.code }
val codes2 = str.toCharArray().map { it.code }
val computed = codes1.zip(codes2) { code1, code2 -> (code1 - code2).absoluteValue }.sum()
Result(idx, str, computed)
}
.minByOrNull { it.computedValue }
println(result) // Output: Result(index=4, string=jad, computedValue=1)
Instead of the helper data class Result a Triple instance could be used:
...
Triple(idx, str, computed)
}
.minByOrNull { it.third }
// Output: (4, jad, 1)
Or if the calculated value is not needed, it could be dropped like that:
...
?.let { it.first to it.second }
// Output: (4, jad)

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.

Check if array contains substring?

I've got this array:
val array : MutableList<String> = mutableListOf("laptop on floor", "man is thomas")
How do I check if it contains this string: flo? (It does, in the first element)
Try this code snippet
val array : MutableList<String> = mutableListOf("laptop on floor", "man is thomas")
val doesContain1 = array.indexOfFirst { it.contains("flo") } >= 0
// or
val doesContain2 = array.find { it.contains("flo") } != null
// or
val doesContain3 = array.any { it.contains("flo") }

Count the number of a

I have this code :
fun main(args:Array<String>){
var a = "banana, eat, one"
var a1 = a1.split("a").toMutableList()
a1.sortBy { it.toCharArray().count { it == 'a' } }
}
This code allows me to sort my list a1 by number of a but I would like to have for each words (banana, eat, one) the number of a. I thought to create a HashMap something like this :
(banana,3)
(eat,1)
(one,0)
But I don't know if there is a function which allows me to do this ?
Could you help me ?
Thank you.
Your existing code didn't compile, but I assume you meant to use a in the second line and split on ,. If so, you can use associateWith to create a Map where the keys are your words, and the values are the counts of 'a' in each:
val a = "banana, eat, one"
val a1 = a.split(", ").toMutableList()
val a2 = a1.associateWith { word -> word.count { char -> char == 'a' } }
println(a2) // {banana=3, eat=1, one=0}
fun main(args:Array<String>){
val input = "banana, eat, one"
// split the words
val split = input.split(",")
val map = HashMap<String, Int>()
for (word in split) {
var countA = 0
// count the character 'a' per word
for (character in word) {
if (character == 'a' || character == 'A') {
countA++
}
}
map[word] = countA
}
println(map)
}
"banana, eat, one".split(",").associateBy({ it }, { it.count { it.toLowerCase() == 'a' } })

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