How to initiate String array in Kotlin? - kotlin

I would like to know how to start an array similar to this String [] errorSoon = {"Hello", "World"}; in Kotlin. How is done?

You can use arrayOf() fuction as it described in Kotlin Basic Type article.
Your code will be the next:
val errorSoon = arrayOf("Hello", "World")

Declare array at global
names = arrayOf(String())
Now in onCreate method Initialize you array with value
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Init array here
names = arrayOf("Friends List", "Notification")
}

val array= arrayOf("Hello", "World")
And there is one more way to create String Array.
// Creates an Array<String> with values ["0", "1", "4", "9", "16"]
val asc = Array(5, { i -> (i * i).toString() })

Try this arrayOf() to create array in Kotlin
val errorSoon = arrayOf("a", "b", "c")
to get values from array use below code
for (i in errorSoon.indices) {
print(errorSoon[i]+" ")
}
You can read more here about it

val errorSoon = arrayOf("Hello", "World")

array of strings can be initialized with square brackets too.
values = [ "a", "b" ]

Related

How to find select the elements that are in one arraylist that are not in another arraylist in kotlin

I am attempting to find the difference of 2 arraylists in kotlin i.e the elements in the first arraylist that are not included in the second arraylist. The code below I believe would work for listOf but I need it to work for arraylists of strings structure instead with the same names i.e first, second and difference should all be arraylists of strings.
fun main() {
private var first = ArrayList<String>()
private var second = ArrayList<String>()
private var difference = ArrayList<String>()
first.add(“a”)
first.add(“b”)
first.add(“c”)
first.add(“d”)
first.add(“e”)
second.add(“a”)
second.add(“b”)
second.add(“c”)
val difference = first.minus(second)
println(difference) // [d, e]
}
You can use arrayListOf:
fun main() {
val first = arrayListOf("a", "b", "c", "d", "e")
println("first type: %s".format(first.javaClass.kotlin.qualifiedName))
val second = arrayListOf("a", "b", "c")
println("second type: %s".format(second.javaClass.kotlin.qualifiedName))
val difference = first.minus(second)
println(difference)
println("difference type: %s".format(difference.javaClass.kotlin.qualifiedName))
}
Or instead, add the elements to the ArrayList's one by one if desired:
fun main() {
val first = ArrayList<String>()
first.add("a")
first.add("b")
first.add("c")
first.add("d")
first.add("e")
println("first type: %s".format(first.javaClass.kotlin.qualifiedName))
val second = ArrayList<String>()
second.add("a")
second.add("b")
second.add("c")
println("second type: %s".format(second.javaClass.kotlin.qualifiedName))
val difference = first.minus(second)
println(difference)
println("difference type: %s".format(difference.javaClass.kotlin.qualifiedName))
}
Output:
first type: java.util.ArrayList
second type: java.util.ArrayList
[d, e]
difference type: java.util.ArrayList

Kotlin: How to flatten list of Hashmaps

How can I flatten a list of HashMaps in Kotlin?
var listOfMaps: List<Map<String, String>> = listOf(mapOf("test" to "test1"), mapOf("test2" to "test3"), mapOf("test4" to "test5"))
I would like to get:Map<String,String> with all key value paires
val map:Map<String, String> = listOfMaps
.flatMap { it.entries }
.associate { it.key to it.value }
you can do something like this if you don't know if the list can be empty.
val map = listOfMaps.fold(mapOf<String, String>()) {acc, value -> acc + value }
If the list never will be empty you can use reduce instead.
Thank you Demigod for the comments
You could use fold:
listOfMaps.fold(
mutableMapOf<String, String>(),
{ acc, item -> acc.also { it.putAll(item) } }
)
The first parameter mutableMapOf<String, String>() creates an empty map to put the values into. This is called the accumulator
The second parameter is a function which takes two arguments
The accumulator
An item from the original list
This function is run sequentially against all items in the list. In our case it adds all the items from each map to the accumulator.
Note: This function does not account for duplicate keys. If a later map has the same key as an earlier one then the value just gets overridden.
Also note (pun intended): We use acc.also {} as we want to return the actual map, not the return value from the addAll method
Well... seeing lots of solutions, I will add my two cents here:
If you don't mind losing the values of duplicated keys you can use something as follows:
listOfMaps.flatMap { it.entries }.associate{ it.key to it.value } // or: it.toPair() if you will
// depending on how large those lists can become, you may want to consider also using asSequence
If you instead want to collect all entries including duplicate keys (i.e. saving all the values), use the following instead (which then gives you a Map<String, List<String>>):
listOfMaps.flatMap { it.entries }.groupBy({ it.key }) { it.value }
Also here the comment regarding asSequence holds...
Finally if you can omit those maps within the list and just use a Pair instead, that will spare you the flatMap { it.entries }-call and make things even easier, e.g. you could just call .toMap() then for the first case and groupBy directly for the second and the question regarding asSequence no longer arises.
An extra addition to this, if you have single value maps, maybe you want to switch to a List<Prair<String, String>>. In that case, the solution is straight forward:
You would have something like:
var listOfMaps: List<Pair<String, String>> = listOf("test" to "test1", "test2" to "test3", "test4" to "test5")
and toMap() would dsolve it all:
listOfMaps.toMap()
If you don't have duplicate keys or don't care for them, you can do it like this:
val flattenedMap = listOfMaps.flatMap { it.toList() }.toMap()
If you have duplicate keys and care for them, you can do it like this:
val flattenedMap = mutableMapOf<String, MutableList<String>>().apply {
listOfMaps.flatMap { it.toList() }.forEach {
getOrPut(it.first) {
mutableListOf()
}.add(it.second)
}
}
The result will be Map<String, List<String>> then of course.
This solution works with same keys (and different collection as values) by merging them together instead of overwriting them
/**
* Merge two maps with lists
*/
fun <K,V>Map<K,Collection<V>>.mergeLists(other: Map<K,Collection<V>>) =
(this.keys + other.keys).associateWith {key ->
setOf(this[key], other[key]).filterNotNull()
}.mapValues { (_,b) -> b.flatten().distinct() }
/**
* Merge two maps with sets
*/
fun <K,V>Map<K,Collection<V>>.mergeSets(other: Map<K,Collection<V>>) =
(this.keys + other.keys).associateWith {key ->
setOf(this[key], other[key]).filterNotNull()
}.mapValues { (_,b) -> b.flatten().toSet() }
Then use like e.g. listOfMaps.reduce { a, b -> a.mergeSets(b) }
Test:
#Test
fun `should merge two maps with as lists or sets`() {
// GIVEN
val map1 = mapOf(
"a" to listOf(1, 2, 3),
"b" to listOf(4, 5, 6),
"c" to listOf(10),
"e" to emptyList()
)
val map2 = mapOf(
"a" to listOf(1, 9),
"b" to listOf(7),
"d" to listOf(null)
)
// WHEN
val mergedAsLists = map1.mergeLists(map2)
val mergedAsSets = map1.mergeSets(map2)
// THEN
listOf(mergedAsLists, mergedAsSets).forEach { merged ->
assertThat(merged.keys).containsOnly("a", "b", "c", "d", "e")
assertThat(merged["a"]).containsOnly(1,2,3,9)
assertThat(merged["b"]).containsOnly(4,5,6,7)
assertThat(merged["c"]).containsOnly(10)
assertThat(merged["d"]).containsOnly(null)
assertThat(merged["e"]).isEmpty()
}
}

Kotlin FP : Convert List<String> to Map<String,Int>

I have a List of String, I want to transform into a Map of occurrences. ( ~ The Map values are the count of many times the String was repeated in the List)
The imperative way, I'd write like the following
fun transformMap(list: List<String>): Map<String, Int> {
val map = mutableMapOf<String,Int>()
for(n in list){
map.put(n,map.getOrDefault(n,0) + 1)
}
return map.toMap()
}
How to write this in Functional Programming way ?
In Java 8+, this will be written like this
String[] note;
Map<String, Integer> noteMap = Arrays.stream(note)
.collect(groupingBy(Function.identity(),
collectingAndThen(counting(), Long::intValue)));
You can use Kotlin's Grouping to do this in one line via the Iterable<T>.groupingBy extension:
val myList = listOf("a", "b", "c", "a", "b", "a")
val myMap = myList.groupingBy { it }.eachCount()
println(myMap)
// Prints {a=3, b=2, c=1}
You can use streams in Kotlin too. But if you want to avoid streams, you can use fold():
val list = listOf("a", "b", "c", "a")
val histogram = list.fold(mutableMapOf<String, Int>()) { map, s ->
map[s] = map.getOrDefault(s, 0) + 1
map
}.toMap()
println(histogram)

merge every two equal elements into another one

How to merge every two equal elements in the list into one element and the merge process is specified by lambda function.
For example if I have a list like this
["a","a","b","b"]
And the merge process is {it.repeat(2)}
it should be like this:
["aa","bb"]
but if the list is like this:
["a","a","a"]
It should be converted to
["aa","a"]
Another example is :
["a","b","a","b"]
will be
["a", "b","a","b"]
I tried zipWithNext() but I can't figure out what to do next especially when there is more than two repeat of the same letter.
How to implement like this in Kotlin using functional programming way of Kotlin.
Here comes the very inefficient but, desired solution. As requested, I've used functional programming as much as possible. Hope you'll like it. But, it would be very easy if you use loop or regular expression to solve this problem.
In this question functional style is not needed.
fun main(args: Array<String>) {
val list = listOf("a", "a", "a", "a", "b", "b", "b", "b")
//val list = listOf("a", "a", "a", "b", "a")
var temp = false
val result = list.zipWithNext().map {
if (temp) {
temp = false
null
} else {
if (it.first == it.second) {
temp = true
it.first + it.second
} else {
it.first
}
}
}.filter { !it.isNullOrBlank() }.toMutableList()
if (!temp) {
result.add(list.last())
}
print(result)
}

Kotlin replace multiple words in string

How to replace many parts of a string with something else in Kotlin using .replace()
For example, we can do it only by replacing one word
fun main(args: Array<String>) {
var w_text = "welcome his name is John"
println("${w_text.replace("his","here")}")
}
and the result will be " welcome here name is John " .
finally we need the result be " welcome here name is alles "
by replacing his to here and john to alles using .replace()
You can do it using multiple consecutive calls to replace():
w_text.replace("his", "here").replace("john", "alles")
You could write an extension that overloads String::replace:
fun String.replace(vararg replacements: Pair<String, String>): String {
var result = this
replacements.forEach { (l, r) -> result = result.replace(l, r) }
return result
}
fun main(args: Array<String>) {
val sentence = "welcome his name is John"
sentence.replace("his" to "here", "John" to "alles")
}
If you have many of those replacement rules, then create a mapping of them and call the replace method in a loop:
val map = mapOf("his" to "here", "john" to "alles", ...)
val sentence = "welcome his name is John"
var result = sentence
map.forEach { t, u -> result = result.replace(t, u) }
println(result)
For the ones interested in replacing a map of values in a text:
private fun replaceText(text: String, keys: Map<String, String>): String =
val replaced = map.entries.fold(text) { acc, (key, value) -> acc.replace(key, value) }
Here is a one liner:
fun String.replace(vararg pairs: Pair<String, String>): String =
pairs.fold(this) { acc, (old, new) -> acc.replace(old, new, ignoreCase = true) }
Test:
#Test fun rep() {
val input = "welcome his name is John"
val output = input.replace("his" to "her", "john" to "alles")
println(output)
output shouldBeEqualTo "welcome her name is alles"
}
Similar to other responses but using Kotlin extension and overloading String::replace to accept a map of oldValue to newValue.
fun String.replace(mapping: Map<String, String>): String {
var str = this
mapping.forEach { str = str.replace(it.key, it.value) }
return str
}
Usage:
val mapping = mapOf("his" to "here", "John" to "alles")
"his dad is John".replace(mapping) // here dad is alles
The issue with just using replace without any regex is:
Let's say I want to replace the occurrence of "here" with "there" inside the string "Where is my bag? Your bag is here." As you can imagine the result will be "Wthere is my bag? Your bag is there." which will not be correct. The solution is to use a regex like given below.
var str = "Where is my bag? Your bag is here."
val replacements = setOf("\\bhere\\b" to "there",
"\\bjohn\\b" to "alles")
replacements.forEach {
str = str.replace(Regex(it.first), it.second)
}