Traverse a list of filter to appy them - kotlin

I have some filter on a list(10..1000).
I would like to have a list of function objects, traverse this list and apply that filter to (10..1000).
Maybe later choose some filters.
fun main(args: Array<String>) {
var sol = (10..1000).toList().filter(lastDigitIsLength ).filter(no7andNo1 ).filter(isEvenAndGreater1).filter(first2DigitsOddCrossSumLess10 ).filter(isPrime )
println("The number is $sol")
}
/* The functions exist

There are few ways to do that.
I've listed them in my example, along with some general comments.
// No need for varargs since Kotlin 1.3
fun main() {
// Prefer vals over vars
val sol = (10..1000).
asSequence().// Use asSequence instead of toList
filter { lastDigitIsLength(it) }. // Block
filter(::no7andNo1). // Method reference
toList()
println("The number is $sol")
}
// Don't know what it means, so lets just always return true
fun lastDigitIsLength(i: Int) = true // Short notation
fun no7andNo1(i: Int): Boolean {
return i % 10 == 7 || i % 10 == 1
}

Sorry, maybe I misunderstand your question. Do you want to apply a list of filters to list of ints? If so, it can be done like this:
fun filter(list: List<Int>, filters: List<(Int) -> Boolean>): List<Int> {
var result = list
for (filter in filters) {
result = result.filter(filter)
}
return result
}
so you can rewrite your function as:
fun main() {
val sol = filter((10..1000).toList(), listOf(::lastDigitIsLength, ::no7andNo1, ::isEvenAndGreater1))
println("The number is $sol")
}

Related

How to create a MutableMap with all keys initially set to same value in Kotlin?

I want to create a mutable map whose keys fall in a continuous range, and values initially set to the same value 9 in a single line using Kotlin. How to do that?
One more option not mentioned in the other answers is to use the associate* function that takes the argument collection that it will put the pairs to:
val result = (1..9).associateWithTo(mutableMapOf()) { 9 }
Unlike .associateWith { ... }.toMutableMap(), this doesn't copy the collection.
If you need to use a different implementation (e.g. a HashMap()), you can pass it to this function, like .associateWithTo(HashMap()) { ... }.
Many collection processing functions in the Kotlin standard library follow this pattern and have a counterpart with an additional parameter accepting the collection where the results will be put. For example: map and mapTo, filter and filterTo, associate and associateTo.
If you mean values, you can use the withDefault function on any Map / MutableMap:
(Playground)
fun main() {
val map = mutableMapOf<String, Int>().withDefault { 9 }
map["hello"] = 5
println(map.getValue("hello"))
println(map.getValue("test"))
}
You can try the following:
val map = object : HashMap<Int, Int>() {
init {
(1..10).forEach {
put(it, 9)
}
}
}
println(map)
I would use associateWith:
val map = (1..9).associateWith { 9 }.toMutableMap()
println(map) // {1=9, 2=9, 3=9, 4=9, 5=9, 6=9, 7=9, 8=9, 9=9}
It also works with other types as key, like Char:
val map = ('a'..'z').associateWith { 9 }.toMutableMap()
println(map) // {a=9, b=9, c=9, d=9, e=9, f=9, g=9, h=9, i=9}
You can use the following way:
import java.util.*
fun main(args: Array<String>) {
val a :Int = 0
val b :Int = 7
val myMap = mutableMapOf<IntRange, Int>()
myMap[a..b] = 9
myMap.toMap()
println(myMap) //Output: {0..7=9}
}

How to conditionally remove specified number of elements from a set in Kotlin

Is there a way to remove only one element(or more generally a specified number of elements) that fits certain criteria from a set.
for example, with the removeif function, it removes all instances that return true for a given condition, but what if I want to remove only one instance?
Here's my code:
fun evaluateGuess(secret: String, guess: String): Evaluation {
val map : HashMap<Char,HashSet<Int>> = hashMapOf('A' to HashSet<Int>(),
'B' to HashSet<Int>(),'C' to HashSet<Int>(),
'D' to HashSet<Int>(),'E' to HashSet<Int>(),'F' to HashSet<Int>())
var rightPos = 0; var wrongPos =0;
for(i in secret.indices){
map.getValue(secret[i]).add(i)
}
for(i in guess.indices){
if(map.getValue(guess[i]).isNotEmpty()){
if(map.getValue(guess[i]).contains(i)){
map.getValue(guess[i]).remove(i)
rightPos++;
}
else{
map.getValue(guess[i]).removeIf { it <i }//want to remove only ONE.
wrongPos++
}
}
}
return Evaluation(rightPos,wrongPos);
}
I don't think there is a standard function for that, whis is what I would do:
/**
* removes up to [n] items fulfilling [condition] in place
*/
fun <T> MutableCollection<T>.removeAmountIfInPlace(n: Int, condition: (T)-> Boolean): MutableCollection<T>{
repeat(n){
firstOrNull(condition)?.let {remove(it)} ?: return this
}
return this
}
/**
* Makes a copy of a Collection and returns that with up to n items fulfilling [condition] removed
*/
fun <T> Collection<T>.removeAmountIf(n: Int, condition: (T)-> Boolean): Collection<T> =
toMutableList().removeAmountIfInPlace(n, condition)
Then, you can go listOf(1,2,3,4,5).removeAmountIf(2){ it > 2} which will give you [1,2,5]

Taking sequence elements fulfilling a predicate then continuing from there in Kotlin

In Kotlin sequences have a takeWhile function that will let you take items as long as they adhere to a given predicate. What I'd like to do is take items according to that predicate, use them in some way, then alter the predicate and take the next "batch". So far I haven't really found a way of doing this purely with what sequences and iterators offer.
Following snippet of code illustrates the problem. The primeGenerator() function returns a Sequence of prime (Long) numbers. Suppose that I want to make lists with each list having prime numbers with the same number of digits. On creating each list I'd use it for some purpose. If the list conforms to what I was searching the iteration can end, otherwise move onto the next list.
val primeIt = primeGenerator().iterator()
var digits = 1
var next: Long? = null
val currentList = ArrayList<Long>()
while (digits < 4) {
next?.also { currentList.add(it) }
next = primeIt.next()
if (next.toString().length > digits) {
println("Primes with $digits: $currentList")
currentList.clear()
digits++
}
}
In this case it ends once the number of digits exceeds 3. This works fine, but I was wondering if there is some way to achieve the same with operations chained purely on the sequence or an iterator of it. Basically chunking the sequence but based on a predicate rather than a set size. The prime number example above is just for illustration, I'm after the general principle, not something that'd only work for this case.
There are no such functions in standard library for large (or infinite) sequences, but you may write such function by yourself (although it requires some extra code):
class BufferedIterator<T>(private val iterator: Iterator<T>) : Iterator<T> {
var current: T? = null
private set
var reachedEnd: Boolean = false
private set
override fun hasNext(): Boolean = iterator.hasNext().also { reachedEnd = !it }
override fun next(): T = iterator.next().also { current = it }
}
fun <T> Iterator<T>.buffered() = BufferedIterator(this)
fun <T> BufferedIterator<T>.takeWhile(predicate: (T) -> Boolean): List<T> {
val list = ArrayList<T>()
if (reachedEnd) return list
current?.let {
if (predicate(it)) list += it
}
while (hasNext()) {
val next = next()
if (predicate(next)) list += next
else break
}
return list
}
fun main() {
val sequence = sequence {
var next = 0
while (true) {
yield(next++)
}
}
val iter = sequence.iterator().buffered()
for (i in 0..3) {
println(iter.takeWhile { it.toString().length <= i })
}
}
With this approach you can easily work even with infinite sequences.
I believe there is a way to accomplish what you want using the standard library. Limit the sequence first and then groupBy the number of digits.
val Int.numberOfDigits
get() = this.toString().length
sequenceOf(1,22,333).takeWhile{ it.numberOfDigits < 3 }.groupBy{ it.numberOfDigits }.values
If you want to avoid the eager evaluation of groupBy you could use groupingBy instead and then reduce potentially leaving the accumulator blank.
ardenit's answer seems like the best reusable approach. Since taking "chunks" of a sequence requires some state it doesn't seem likely something easily done in a purely functional manner. Delegating the state to a separate class enveloping the sequence makes sense.
Here's a small snippet showing what I ended up using. This assumes the sequence will not be empty and is (technically) infinite or further results aren't requested at some point.
class ChunkedIterator<T>(seq: Sequence<T>) {
private val it = seq.iterator()
var next: T = it.next()
fun next(predicate: (T) -> Boolean): List<T> {
val result = ArrayList<T>();
while (predicate.invoke(next)) {
result.add(next)
next = it.next();
}
return result
}
}
one way you could achieve this is by getting an iterator from your your original sequence and then building a new sequence out of it for each "take" -
val itr = seq.iterator()
val batch1 = itr.asSequence().takeWhile { predicate1(it) }.toList()
val batch2 = itr.asSequence().takeWhile { predicate2(it) }.toList()

Сheck if map contains substring. Kotlin

I have a
val map = Map<String,String>
map.put("Nurseiyt","android")
I want to get a value by subString like:
map["Nurs"] should return "android"
is it possible?
Use kotlin.Collections, there are methods like filter.
Two things - it's better to use regular expression. So, you can even get better control what will be returned. And the second one, there can be more than one elements matched to that regex. So that's why I return list.
fun <T> substringKey(map: Map<String, T>, regex: Regex): List<T> {
return map.filter { it.key.contains(regex) }
.map { it.value }
}
If you want to use that notation you need to create your own map and override proper operator. What's worth to notice, you cannot return list of values then. So, in this case I just return first found value.
class SubstringMap<V> : HashMap<String, V>() {
override operator fun get(key: String): V? {
return this.entries.first { it.key.contains(key) }.value
}
}
fun main() {
val map = SubstringMap<String>()
map["Nurseiyt"] = "android"
println(map["Nurs"]) // "android"
}
And as the last thing - in kotlin you can create your own operator, like withKeyPart. This would be much better than overriding default operator (because I wouldn't expect that [] operator will work in different way than usual.
infix fun <V> Map<String, V>.withKeyPart(keyPart: String): List<V> {
return this.filter { it.key.contains(keyPart) }
.map { it.value }
}
and then call it like this:
fun main() {
val map = HashMap<String, String>()
map withKeyPart "KeyPart" // infix notation
map.withKeyPart("KeyPart") // standard call
}
Filtering the map, as per other answers, is simple and straightforward, but it doesn't scale well; it takes time proportional to the size of the map, so if the map could grow big, it could get very slow.
If you're always going to be searching for a leading substring, i.e. the start of a map key, then a better general solution is a data structure called a trie.  This lets you search efficiently, with just one lookup per character.
Of course, writing one from scratch may not be justified for your project.  But there are third-party implementations you could use, such as this one in Apache Commons.  Or see the answers to this question.
write top level function like this
fun HashMap<String, String>.getContainskeyValue(search: String): String?
{
var returnList = ArrayList<String?>()
this.keys.filter { it.contains(search) }.map {
returnList.add(this[it])
}
return returnList.first()
//if you want all keys 'contains' values just return list
/* Ex
map.put("Nurseiyt", "android")
map.put("Nurseiyt1", "androidone")
map.put("Nurseirt2", "andrrroidtwo")
val isContainsdata = map.getContainskeyValue("N")
println(" result " + containsdata)
output :result [andrrroidtwo, android, androidone]
*/
}
then call like this
val map = HashMap<String, String>()
map.put("Nurseiyt", "android")
val containsdata = map.getContainskeyValue("Nurs")
println(" result " + containsdata)
output
android

How can I change this to use "for loop" instead of `forEach`

I'm struggling to change it to use a for loop and still do the same thing.
The program is supposed to read a file with some flights and this specific part of the program needs to read the file using two different days that the user inputs then it needs to show how many passengers there are per flight and each day.
And how it's done now works but I'm trying to change it to use a for loop as I said before but doesn't work because I don't know how to do the same thing as map does but only in the fun interval.
fun interval(reservas: List<Reservas>, dayInferior: Int, daySuperior: Int) {
val map = mapReservas(reservas)
for(day in dayInferior..daySuperior) {
map.forEach {
val reservasNum = it.key.first
val reservasDay = it.key.second
val reservasCount = it.value.count()
if (reservasDay == day) {
println("$reservasNum has $reservasCount passengers on day $day")
}
}
}
println()
println("Press Enter")
readLine()
}
fun mapReservas(reservas: List<Reservas>): Map<Pair<String, Int>, List<Reservas>> {
val map = mutableMapOf<Pair<String, Int>, MutableList<Reservas>>()
for (reserva in reservas) {
val key = reserva.numFlight to reserva.day
val list = map[key] ?: mutableListOf()
list.add(reserva)
map[key] = list
}
return map
}
All your code can be replaced only with one function.
fun interval(reservas: List<Reservas>, dayInferior: Int, daySuperior: Int) {
reservas.groupBy { reserva -> reserva.day to reserva.numFlight }
.filter { (key, _) -> key.first in dayInferior..daySuperior }
.forEach { (key, reservas) ->
val (reservasNum, reservasDay) = key
val reservasCount = reservas.count()
println("$reservasNum has $reservasCount passengers on day $reservasDay")
}
println()
println("Press Enter")
readLine()
}
Explaining:
As I undestand, at first you trying to group all your Reservas by day and numFlight. It can be done via one function groupBy where you pass pair of day and numFlight.
Filter all Reservas by day. It can be done by checking if day belongs to range dayInferior..daySuperior (operator in).
Print all reservas by using forEach.
Other things
Destructing declarations
val reservasNum = it.key.first
val reservasDay = it.key.second
same as
val (reservasNum, reservasDa) = it.key
Omitting one unused parameter in lamda:
.filter { (key, _) -> ... }
If you iterate with a for loop over the Map each element is a Pair. If you write (pair, list) you destructure each Pair which itself consists of a Pair and a List.
fun interval(reservas: List<Reservas>, dayInferior: Int, daySuperior: Int) {
val map = mapReservas(reservas)
for(day in dayInferior..daySuperior) {
for((pair, list) in map) {
val reservasNum = pair.first
val reservasDay = pair.second
val reservasCount = list.count()
// ...
}
}
// ...
}
Maybe this makes it more clear:
for(outerPair in map){
val (innerPair, list) = outerPair
val reservasNum = innerPair.first
val reservasDay = innerPair.second
val reservasCount = list.count()
// ...
}
I left this function (mapReservas) untouched intentionally, because maybe you are using it somewhere else. But you can improve it right away by using Type aliases (since Kotlin 1.1).
typealias FlightNum = String
typealias Day = Int
fun mapReservas(reservas: List<Reservas>):
Map<Pair<FlightNum, Day>, List<Reservas>> {
// ...
}
As you can see the code becomes much more readable if you use the destructure syntax and Type aliases.