How to get collection values in Kotlin lambda - kotlin

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 }

Related

Write a kotlin program that prints the number that is repeated the most in a consecutive way

I'm kind of stuck, I don't know how to make the second loop to start 1 position above the first loop in Kotlin.
I have an array (named myArray) with 10 elements, I need to Write a Kotlin program that prints the number that has the most consecutive repeated number in the array and also prints the number of times it appears in the sequence.
The program must parse the array from left to right so that if two numbers meet the condition, the one that appears first from left to right will be printed.
Longest: 3
Number: 8
fun main() {
val myArray: IntArray = intArrayOf(1,2,2,4,5,6,7,8,8,8)
for((index , value) in myArray.withIndex()){
var inx = index + 1
var count = 0
var longest = 0
var number = 0
for((inx,element) in myArray.withIndex()) {
if(value == element ){
count+=
}
}
if(longest < count){
longest = count
number = value
}
}
}
I'm against just dropping answers, but it is quite late for me, so I'll leave this answer here and edit it tomorrow with more info on how each part works. I hope that maybe in the meanwhile it will help you to gain some idea to where you might be going wrong.
val results = mutableMapOf<Int, Int>()
(0..myArray.size - 2).forEach { index ->
val current = myArray[index]
if (current == myArray[index + 1]) {
results[current] = (results[current] ?: 1) + 1
}
}
val (max, occurrences) = results.maxByOrNull { it.value } ?: run { println("No multiple occurrences"); return }
println("Most common consecutive number $max, with $occurrences occurrences")
Alternatively if the intArray would be a list, or if we allowed to change it to a list myArray.toList(), you could replace the whole forEach loop with a zipWithNext. But I'm pretty sure that this is a HW question, so I doubt this is the expected way of solving it.
myList.zipWithNext { a, b ->
if (a == b) results[a] = (results[a] ?: 1) + 1
}

Compose maps using key and value in Kotlin

I have two maps and I want to merge using some rules
val a = mapOf(1 to 101, 2 to 102, 3 to 103)
val b = mapOf(101 to "a", 102 to "b", 103 to "c")
is there a way to merge using values for a and key for b
val result = mapOf(1 to "A", 2 to "b", 3 to "c")
Since the values of a and the keys of b will always match, you can do this with a single mapValues
val result = a.mapValues { (_, v) -> b.getValue(v) }
getValue can be safely used here since the key v always exist in b as a consequence of our assumption.
In general, if b may not have all the values of a as keys, you can do:
val result = a.entries.mapNotNull { (k, v) -> b[v]?.let { k to it } }.toMap()
This removes the key from the result, if the key's corresponding value in a doesn't exist as a key in b. You can also use this as an alternative if you don't like the !! in the first solution.
mapNotNull and toMap loops through the entries one time each. If that is a problem for you, use asSequence:
a.asSequence().mapNotNull { (k, v) -> b[v]?.let { k to it } }.toMap()
Since you're sure each value from map a is present in map b, this should be as simple as using mapValues and using the value of that key in map b
a.mapValues { entry ->
b[entry.value]
}
Due to having to edit and redo my answer, #Sweeper beat me to it and provided a more in-depth answer.

Kotlin For loop start from a given index

I want to start a For loop from a given index
in Java you can easily write
for (int i = startingIndex; i < items.size(); i++)
how to to do that in Kotlin?
I know how to write a for loop in Kotlin
my example
I want to iterate over an array of strings but the start position is 3, not iterating over a Range the iteration will be over a collection of items
For iterating from the start item till the last, you can use something like this:
for (i in startingIndex until items.size) {
//apply your logic
}
Another option is to drop first n elements and use forEach from there:
val l = listOf(1, 2, 3, 4)
l.drop(1).forEach { println(it) } // prints "2, 3, 4"
Instead of iterating over the items in your array, you can iterate over the indices and access the array by index. Here's a simple example.
val otherStrings = arrayOf("a", "b", "c", "d", "e")
for (i in 3..otherStrings.size-1)
println(otherStrings[i])
This iterates from starting index 3 to the last index (which is size - 1)
If the function is repeated several times you could do this:
Create an extension function
List<String>.startByIndex(startingIndex : Int){
for(index in startingIndex until this.size){
//apply common logic
}
}
call the extension function from your string list
var startIndex : Int = 3 // example
items.startByIndex(startIndex)
P.S. : If, for example, the extension function must always return a string as output, you have to change everything like this:
List<String>.startByIndex(startingIndex : Int) : String {
for(index in startingIndex until this.size){
var result : String
//apply common logic and instantiate var result
return result
}
}
var startIndex : Int = 3 // example
var result : String = items.startByIndex(startIndex)

Kotlin Is there a way to flatten Map<K out T , List<V out T> to List<T>

I would like to transform the Map to List
e.g I have
mapOf("a" to listOf(1,2),
"b" to listOf(3,4)
)
I want the result to be
listOf("a", 1, 2, "b", 3, 4)
order must be Key and its Values, Key and its Values, ...
is there some function in kotlin that could help me with that?
My second comment variant as answer for a Map<String, List<Int>>:
mapOf("a" to listOf(1,2),
"b" to listOf(3,4))
.flatMap { (key, values) -> listOf(key) + values }
which gives a List<Any> with the keys followed by their values.
This example makes use of destructuring declaration and Map.flatMap.
UPDATE: the answer below was written before the question was updated and changed how the map was created (see the history of the question for details). As the question now stands, the answer below will no longer work. It does work for the question as originally asked though, I believe.
#Roland is right that your map will never result in that list because there can only ever be a single value in the map against any given key. So I think you need to replace that map with a list of pairs. You can then group it and flatmap it to get your desired result:
val pairs = listOf("a" to 1, "a" to 2, "b" to 3, "b" to 4)
val result = pairs
.groupBy { it.first }
.flatMap { (key, values) -> listOf(key).plus(values.map { it.second }) }
Another slightly different option which you might decide is more readable is this:
val result = pairs
.groupBy({ it.first }, { it.second })
.flatMap { (key, values) -> listOf(key).plus(values) }
You can flatMap over map.entries. Have a look at this function:
val map = mapOf("a" to listOf(1,2),
"b" to listOf(3,4))
println(map)
val flattened : List<Any> = map.entries.flatMap {entry ->
//create list with key as only element, must be type <Any> to add other stuff later
val list = mutableListOf<Any>(entry.key)
//add values
list.addAll(entry.value)
list
}
println(flattened)
prints:
{a=[1, 2], b=[3, 4]}
[a, 1, 2, b, 3, 4]
#Rolands answer inspired this even simpler, more idiomatic version. It essentially does the same, but crams everything into one line:
val flattened: List<Any> = map.flatMap {entry ->
listOf(entry.key) + entry.value
}

Simplifying the predicate when checking for several known values

Kotlin often uses very pragmatic approaches. I wonder whether there is some I don't know of to simplify a filter predicate which just asks for some known values.
E.g. consider the following list:
val list = listOf("one", "two", "2", "three")
To filter out "two" and "2" filtering can be accomplished in several ways, e.g.:
list.filter {
it in listOf("two", "2") // but that creates a new list every time... (didn't check though)
}
// extracting the list first, uses more code... and may hide the list somewhere sooner or later
val toCheck = listOf("two", "2")
list.filter { it in toCheck }
// similar, but probably less readable due to naming ;-)
list.filter(toCheck::contains)
// alternative using when, but that's not easier for this specific case and definitely longer:
list.filter {
when (it) {
"two", "2" -> true
else -> false
}
}
// probably one of the simplest... but not so nice, if we need to check more then 2 values
list.filter { it == "two" || it == "2" }
I wonder... is there something like list.filter { it in ("two", "2") } or any other simple way to create/use a short predicate for known values/constants? In the end that's all I wanted to check.
EDIT: I just realised that the sample doesn't make much sense as listOf("anything", "some", "other").filter { it in listOf("anything") } will always be just: listOf("anything"). However, the list intersection makes sense in constellations where dealing with, e.g. a Map. In places where the filter actually doesn't return only the filtered value (e.g. .filterKeys). The subtraction (i.e. list.filterNot { it in listOf("two", "2") }) however also makes sense in lists as well.
Kotlin provides some set operations on collections which are
intersect (what both collections have in common)
union (combine both collections)
subtract (collections without elements of the other)
In your case, instead of filter, you may use the set operation subtract
val filteredList = list.subtract(setOf("two","2"))
and there you go.
EDIT:
and the fun (pun intended) doesn't end there: you could extend the collections with your own functions such as a missing outerJoin or for filtering something like without or operators i.e. / for intersect
For example, by adding these
infix fun <T> Iterable<T>.without(other Iterable<T>) = this.subtract(other)
infix fun <T> Iterable<T>.excluding(other Iterable<T>) = this.subtract(other)
operator fun <T> Iterable<T>.div(other: Iterable<T>) = this.intersect(other)
Your code - when applied to your example using the intersect - would become
val filtered = list / filter //instead of intersect filter
or - instead of substract:
val filtered = list without setOf("two", "2")
or
val filtered = list excluding setOf("two", "2")
Pragmatic enough?
I ended up with the following now:
fun <E> containedIn(vararg elements: E) = { e:E -> e in elements }
fun <E> notContainedIn(vararg elements: E) = { e:E -> e !in elements }
which can be used for maps & lists using filter, e.g.:
list.filter(containedIn("two", "2"))
list.filter(notContainedIn("two", "2"))
map.filterKeys(containedIn("two", "2"))
map.filterValues(notContainedIn("whatever"))
In fact it can be used for anything (if you like):
if (containedIn(1, 2, 3)(string.toInt())) {
My first approach inspired by Gerald Mückes answer, but with minus instead of subtract (so it only covers the subtraction-part):
(list - setOf("two", "2"))
.forEach ...
Or with own extension functions and using vararg:
fun <T> Iterable<T>.without(vararg other: T) = this - other
with the following usage:
list.without("two", "2")
.forEach... // or whatever...
With the above variant however no infix is possible then. For only one exclusion an infix can be supplied as well... otherwise the Iterable-overload must be implemented:
infix fun <T> Iterable<T>.without(other : T) = this - other
infix fun <T> Iterable<T>.without(other : Iterable<T>) = this - other
Usages:
list without "two"
list without listOf("two", "2")
I don't think there is anything simpler than to create the filtering list/set and then apply it:
val toCheck = listOf("two", "2")
val filtered = list.filter { it in toCheck }
or
val toCheck = setOf("two", "2")
val filtered = list.filter { it in toCheck }
but if you prefer you can create a Predicate:
val predicate: (String) -> Boolean = { it in listOf("2", "two") }
val filtered = list.filter { predicate(it) }
Edit: as for the approach with minus, which is not the case here but has been mentioned, it does not provide simplicity or efficiency since itself is using filter:
/**
* Returns a list containing all elements of the original collection except the elements contained in the given [elements] collection.
*/
public operator fun <T> Iterable<T>.minus(elements: Iterable<T>): List<T> {
val other = elements.convertToSetForSetOperationWith(this)
if (other.isEmpty())
return this.toList()
return this.filterNot { it in other }
}
(from Collections.kt)