merge/union two string sub arrays inside a json array kotlin - kotlin

is there anyway we can merge/union the two sub arrays inside a json array
jsonArray = [["abc","hello","hai"]["true","false","hai"]]
expected output would be ["abc","hello","hai","true","false"]
any help would be highly appreciated!
Thanks

You could first flatten it and then turn it into a Set to remove duplicates. For example:
val jsonArray = listOf(listOf("abc","hello","hai"), listOf("true","false","hai")) // This is the same as [["abc","hello","hai"]["true","false","hai"]]
val flattenedSetOfJsonArray = map.flatten().toSet()
println(flattenedSetOfJsonArray) // prints [abc, hello, hai, true, false]
Edit
If you want to flatten deeply nested lists you can use this helper method (credits to)
fun List<*>.deepFlatten(): List<*> = this.flatMap { (it as? List<*>)?.deepFlatten() ?: listOf(it) }
Now use this method like this:
val jsonArray = listOf(listOf("abc","hello","hai"), listOf("true","false","hai"), listOf(listOf("true", "false", "abc")))
val flattenedSetOfJsonArray = jsonArray.deepFlatten().toSet()
println(flattenedSetOfJsonArray) // prints [abc, hello, hai, true, false]

Related

How to remove String from a ListOf Strings in Kotlin?

I have a listOf Strings
val help = listOf("a","b","c")
And want to remove b from the list but not using index because I will get Strings randomly like this
val help = listOf("c","a","b")
How to do this?
You can filter the List using the condition item does not equal "b", like…
fun main(args: Array<String>) {
// example list
val help = listOf("a","b","c")
// item to be dropped / removed
val r = "b"
// print state before
println(help)
// create a new list filtering the source
val helped = help.filter { it != r }.toList()
// print the result
println(helped)
}
Output:
[a, b, c]
[a, c]
Lists by default aren't mutable. You should use mutable lists instead if you want that. Then you can simply do
val help = mutableListOf("a","b","c")
help.remove("b")
or you can do it like this if help really needs to be a non-mutable list
val help = listOf("a","b","c")
val newHelp = help.toMutableList().remove("b")
using a filter like in deHaar's answer is also possible

About binarySearch() of Kotlin List

I ran the examples in the official Kotlin documentation in the local Android Studio, and found that the results are different from what I expected, but I don’t know what is causing this?
data class Produce(
val name: String,
val price: Double
)
This is the data class I defined
val list2 = listOf(
Produce("AppCode", 52.0),
Produce("IDEA", 182.0),
Produce("VSCode", 2.75),
Produce("Eclipse", 1.75)
)
this is my source list
println(list2.sortedWith(compareBy<Produce> {
it.price
}.thenBy {
it.name
}))
The output on the console is:
[Produce(name=Eclipse, price=1.75), Produce(name=VSCode, price=2.75), Produce(name=AppCode, price=52.0), Produce(name=IDEA, price=182.0)]
I call binarySearch() like this
println("result: ${
list2.binarySearch(
Produce("AppCode", 52.0), compareBy<Produce> {
it.price
}.thenBy {
it.name
}
)
}")
I think the result should be 2, but it is 0
result: 0
I don't know why it turned out like this. Plase help me . thanks a lot
sortedWith() does not modify the list, it returns a new, sorted collection. When calling list2.binarySearch() you still search through original, unsorted list.
You need to either do something like:
list2.sortedWith().binarySearch()
Or create your list with mutableListOf() and then use sort() which sorts in-place.
Broot is right. You need to pass the sorted list to the binarySearch() function. To clarify in code:
val comparator = compareBy<Produce> { it.price }.thenBy { it.name }
val sorted = list2.sortedWith(comparator)
println(sorted.joinToString("\n"))
val foundIndex = sorted.binarySearch(Produce("AppCode", 52.0), comparator)
println("Found at: $foundIndex")
Result:
Produce(name=Eclipse, price=1.75)
Produce(name=VSCode, price=2.75)
Produce(name=AppCode, price=52.0)
Produce(name=IDEA, price=182.0)
Found at: 2

Kotlin short-cut to assign value to variable using stream function or other

for (i in 0 until result.size){ result[i].config= addConfig(taskNames!![i],processKeys!![i]) }
Here result is a list of class which has datamember config and tasNames and processKeys are list of string.
Is there a way in kotlin to map result.config with respective taskNames and processKeys without using traditional loop and mentioning length of result.I am new to kotlin.
class Process {
var processKey: String? = null
var task: List<Task>? = null}
class Task {
var taskName: String? = null
var processVariables: List<ProcessVariable>? = null}
class ProcessVariable {
var name: String? = null
var label: String? = null
var applicableValue: List<String>? = null}
Result is already present with datamember config pf type ProcessVariable
If I understand your problem correctly, you need to combine 3 lists.
So iterating over the lists may be easier to understand than some clever way of list transformations.
You can get rid of the traditional for loop, so you don't need to calculate the size of the loop:
result.forEachIndexed {
i, resultData -> resultData.config = addConfig(taskNames[i], processKeys[i])
}
If you want to combine two lists, you can use the zip method:
val configList = taskNames.zip(processKeys) {tsk, prc -> addConfig(tsk, prc)}
In your example, the result-object was already existing. Maybe it is easier to create new result-objects:
val results = configList.map {
Result(config = it)
}

How to sort a string alphabetically in Kotlin

I want to reorder the string "hearty" to be in alphabetical order: "aehrty"
I've tried:
val str = "hearty"
val arr = str.toCharArray()
println(arr.sort())
This throws an error. I've also tried the .split("") method with the .sort(). That also throws an error.
You need to use sorted() and after that joinToString, to turn the array back into a String:
val str = "hearty"
val arr = str.toCharArray()
println(arr.sorted().joinToString("")) // aehrty
Note: sort() will mutate the array it is invoked on, sorted() will return a new sorted array leaving the original untouched.
So your issue is that CharArray.sort() returns Unit (as it does an in-place sort of the array). Instead, you can use sorted() which returns a List<Char>, or you could do something like:
str.toCharArray().apply { sort() }
Or if you just want the string back:
fun String.alphabetized() = String(toCharArray().apply { sort() })
Then you can do:
println("hearty".alphabetized())

In Kotlin, how can I take the first n elements of an array

In Kotlin, how can I take the first n elements of this array:
val allColours = arrayOf(
Pair(Color.RED, Color.WHITE),
Pair(Color.RED, Color.BLACK),
Pair(Color.YELLOW, Color.BLACK),
Pair(Color.GREEN, Color.WHITE),
Pair(Color.BLUE, Color.WHITE),
Pair(Color.BLUE, Color.WHITE),
Pair(Color.CYAN, Color.BLACK),
Pair(Color.WHITE, Color.BLACK))
So how can I fill pegColours with the first say 3 Pairs?
var pegColours: Array<Pair<Color,Color>> = //???
I tried allColours.take but it gave an error:
Expecting an element
You need to specify the number of items you want to take.
allColours.take(3)
For a random number of random indices, you can use the following:
val indexes = arrayOf(2, 4, 6)
allColours.filterIndexed { index, s -> indexes.contains(index) }
Note that you can write an extension method for this:
fun <T> Array<T>.filterByIndices(vararg indices: Int) = filterIndexed { index, _ -> indices.contains(index) }
Alternatively, if the indices are consecutive, you can use slice:
allColours.slice(1..3)
The problem with your code that you create pairs with color constants which are Ints (allColours has type Array<Pair<Int, Int>>), but you expect Array<Pair<Color, Color>>. What you have to do is change type pegColours type and use take:
var pegColours: Array<Pair<Int, Int>> = allColours.take(3).toTypedArray()
Also you have to call toTypedArray() cause Array.take returns List rather than Array. Or you can change pegColours type as following:
var pegColours: List<Pair<Int, Int>> = allColours.take(3)
I know you already proposed the usage of take, but alternatively ranges and a simple map also help to write idiomatic code as shown next:
var pegColours = (0 until 3)
.map { allColours[it] }
.toTypedArray()
You are very close :)
val allColours = arrayOf("red", "blue", "green")
kotlin.io.println(allColours.take(2))
Will give you first two elements ["red", "blue"]
You have to specify the number of elements you want to take from the array