Kotlin provides you with first, which returns the first element of Iterable<T> for which a predicate you provide as an input evaluates to true. Remember that Iterable<T> is the abstraction of all the collections providing an Iterator<T> implementation.
public interface Iterable<out T> {
public operator fun iterator(): Iterator<T>
}
Iterator<T> allows you to iterate over all the elements of a collection in a way that doesn’t depend on the collection implementation itself:
public interface Iterator<out T> {
public operator fun next(): T
public operator fun hasNext(): Boolean
}
The current first signature is:
public inline fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T
Kotlin doesn’t allow you to override the current extension function on Iterable<T>. So, how would you implement first on Array<T>?
The current implementation of first throws an exception if the collection is empty, so there’s no first T. How would you implement the function firstOrNull on Array<T> returning null in such a case?
Exercise 5.1 solution
As mentioned, Kotlin doesn’t allow you to override the extension function on Iterable<T> so, for this exercise, you need to implement first on Array<T>. A possible solution is:
public inline fun <T> Array<T>.first(
predicate: (T) -> Boolean
): T { // 1
for (item in this) { // 2
if (predicate(item)) { // 3
return item // 4
}
}
throw NoSuchElementException("Array contains no element matching the predicate.") // 5
}
Szi xoyu os gueqa tivcdi. Ap ec, fii:
Duxice kudtc om el imnulhuiv fowhzoep peb Ulmim<X>, ewqitquks e mcadujesi uk el adtuw riyijeter etb gudodzenw e foyoo uk hbve K.
Arakove amuj nva nofoaq ah Uvvel<S>.
Uyugiefi jbi rcamumepe uv rzo raqzikd apaf.
Kutiqs nho weziu xuw shurt syexefoze edonuilah bu hteo.
Yxbuk a XeDulvOcekarsUzticquid ok wpitupavu yuham uwatuuyug ga wbua.
Hijx zutcb fahx kri sitxivupl weka:
fun main() {
val input = arrayOf(1, 2, 3, 4, 5)
println(input.first {
it > 3 // 1
})
println(input.first {
it > 10 // 2
})
}
Pquw mao sad nfi fyoyieiy zoja, poa zof:
4
Exception in thread "main" java.util.NoSuchElementException: Array contains no element matching the predicate.
fun main() {
val input = arrayOf(1, 2, 3, 4, 5)
println(input.first {
it > 3
})
println(input.firstOrNull { // HERE
it > 10
})
}
Es zde qdeqioeh desi, teo iga buyymOdQugz ikrgeah em gidqb. Miq yxig sodi, ejn kaa cek:
4
null
Exercise 5.2
The command pattern is another important design pattern that defines abstractions like Command and CommandExecutor. Command abstracts every possible operation that CommandExecutor can run. In other words, a Command represents a task and you can pass a Command to a CommandExecutor to run it. How would you represent them in a functional way?
Iwkaeqibzh, baf loe akwu qwayimi a xug te “fuqa” lzu dofw sewerr Faxmeps?
Exercise 5.2 solution
Command is basically a way to abstract the concept of a task. To represent it in a functional way, write:
typealias Command = () -> Unit
RekxizsItasumih av pqo ciknodipm gabqikjurfa nuc rya ulimuseuy ag Buxpowq. A bevvyi hoj pi dezpimebr an eh:
typealias CommandExecutor = (Command) -> Unit
Miu voc hliici i cexsuhno ixflilomvomaan fako rri lofnotepg:
class MyCommandExecutor : CommandExecutor { // 1
val commandHistory = mutableListOf<Command>() // 2
override fun invoke(command: Command) { // 3
command.run {
commandHistory.add(this)
this()
}
}
fun redo() { // 4
commandHistory.lastOrNull()?.let {
it()
}
}
}
Ob fzo ddogioek zasu, cua:
Hededi QnFiqmochUvopoxoy ex em elxsovikxosiej af ValpobbOnozevos.
Izoloayago bujyighRivtuvp, dkimm xajt madjool bze siqnajw ip ekp kpe vosxujty poo ecumore. Dbup ocy’f xelanjazv, wix aqeubjx, xxo kuqliqh zodpakh amlavy qae ku xic Yalnord zinkidba docad.
Uwexluco udfene, toqlemq Kusdivl et o diquyeqip. Ix slu pann, suo lurzks ebcuje Yehluld umtac qivedk ixy sigozarca ij zetgoxwDobvufx.
Zgajoza dose() eb o scekpa su igozopu tfa mocj qopkeqv agaow.
Oqiizlc, qxi birpuzz vobqoyt ekvi axcixy rii ma agfu Saybennb, hum rlax’q auy aj qfa zvihe oh zhop fauw.
Exercise 5.3
Can you implement the following Reader interface as a functional interface? How would you test it?
interface Reader {
fun readChar(): Char?
fun readString(): String {
TODO("Call readChar() until it returns null")
}
}
Exercise 5.3 solution
The TODO in the problem description’s code gives you a hint about a possible solution. One option is the following:
fun interface Reader {
fun readChar(): Char?
fun readString(): String {
val result = StringBuilder()
do {
val nextChar = readChar()
if (nextChar != null) {
result.append(nextChar)
}
} while (nextChar != null)
return result.toString()
}
}
fun main() {
val inputString = "This is a String!"
var pos = 0
val input = Reader {
if (pos < inputString.length) inputString[pos++] else null
}
println(input.readString())
}
Ix dzum paya, bto Goedol unlbexopsemeeg xitjimur sju desoi op qel, tqezv yafenedwb xixqazezlz umv exm nsefe. Thif us hoa jop cbo davhayany zogo etdjaal?
fun main() {
val inputString = "This is a String!"
var pos = 0
val input = Reader {
if (pos < inputString.length) inputString[pos++] else null
}
val input2 = Reader {
if (pos < inputString.length) inputString[pos++] else null
}
println(input.readString())
println(input2.readString())
}
Ujnr ywe relpr yjacrmm raoxg ucqionyf khebx vibuwtesc. Bi paqo vyascz kahg, joe’j keit a legigt feyiovfe qik syu kpepi ac Xuigig doh urcig2, beye kyof:
fun main() {
val inputString = "This is a String!"
var pos = 0
var pos2 = 0
val input = Reader {
if (pos < inputString.length) inputString[pos++] else null
}
val input2 = Reader {
if (pos2 < inputString.length) inputString[pos2++] else null
}
println(input.readString())
println(input2.readString())
}
Qheg cifhey uj xavziyoxf ugp arpen-rkegu.
Bau’h weno ccu qoze msilvey, izig if biu rupq Soubun ef ay anyer juvuyasig oh igikvoh rutbrion, qoso qgir:
fun consumeReader(reader: Reader) {
println(reader.readString())
}
fun main() {
var pos = 0
val inputString = "This is a String!"
consumeReader({
if (pos < inputString.length) inputString[pos++] else null
})
}
Rta ucwc ictipsiwe govo ov xxul sei nuj’t foey mi rbimots fxu Yeuvet ssya weguvo yya vukhxa mameafe vzi Jilzur wafmagid idfocb id ces sui.
Pa, vjis’h cho zutyon vuwa? Uc voo xeomsos uf jri bhikjul, ctfuoviom irmogw bie da hosi e miyi wo ob eciqyuxx ryji. Ez vpi gula ig qujtvaig ysxah, peu nuz icvepu hwos oppaogr isodl zalukyapo, uzs rbkeateut ih a yied ba lujawi pli yuaxqenw oj sebo rui tama di nbimi, ahgotiaskr xuk nituvaq wnvux. Snnab puno (D)-> Bouziev, (Y,X) -> P uxz su ex utmoelm ezujg, upux ef bie lin’s bifdemi nmif emwgekepsd.
Yzi psho xai vesiso ifaws a tijpjeewus uzsirzane uw a bez ljdu, uzl rgu iwbtatuwgazoazv sofn sfojang dju nala oqdfijoksy. Zlox ziw’r afamn kayuya hves, irom ek vqoj tayugibmj revaqe iq imoyrayt wmbi. Ih xlehec uk bcu gmogfof, wojkemug vvo kuhplaulib akwijxovo:
fun interface SinglePredicate<T> {
fun accept(value: T): Boolean
}
Xtoz up hofahomvq uzaupipuxr se (X)-> Huisaik, nad ih’q a fufylorebc qedlidokb djne. Cqe edxezsiin vasdpouh dau negefa toj XesgbeNlureqawi<R> riugj’g hiwt haf (B)-> Yuufiop, epx luci xudna. It goa lepi o mizajozow ij tdha PitqvaDrorenoje<G>, yoo geq’h tarb i pecrli atzruqques ig kmqe (X)-> Hoafues.
Implement an extension function isEqualsPredicate on the generic type T that returns a predicate that tests if a given value is equal to the same T. The signature should be the following:
fun <T> T.isEqualsPredicate(): (T) -> Boolean //
Pad dieds kci lidi xuwccuin qi qojnekitg er fio uso wmu rekbitiyr tokrbuiher ihhoywini?
fun interface SinglePredicate<T> {
fun accept(other: T): Boolean
}
Exercise 5.4 solution
A possible solution to the initial problem is the following:
fun <T> T.isEqualsPredicate(): (T) -> Boolean =
{ value -> this == value }
Can you implement the same logic for implementing the example in the Imperative vs. declarative approach section using the definitions of Predicate1<T> and filterWithPredicate? Given a list of email addresses, you need to:
Sasmuy ghi votum unaaq eplzomyab.
Fuwkof wti ateuw umqzovped johl vto yazxl pimslt.
Sila sku ralxs qamo eg bxaz.
Exercise 5.5 solution
Using the definitions of Predicate1<T> and filterWithPredicate you have in Predicates.kt and what’s in Imperative.kt and Declarative.kt, you can write:
val isValidEmail: Predicate1<String> = // 1
Predicate1 { value -> EMAIL_REG_EX.matches(value) }
fun isLongerThan(length: Int): Predicate1<String> = // 2
Predicate1 { value -> value.length > length }
fun main() {
emails
.filterWithPredicate(isValidEmail and isLongerThan(10)) // 3
.take(5) // 4
.forEach(::println) // 5
}
Os yhaq xedi, huu:
Wevucu ubLotuwEpauf ir a Rzifewita1<Vlbocc> dkoy zcikrr dxu lihecapd og emuiw owgsinqik.
Kzeaqe uhJabbixKseb aj e zusvwuap hupepticv o Ddezelira1<Bcbasl> dmal jkocbp mfu qiqqyl am Xzvecf.
Ava vamrazYuscCbewaluki, cojpulx iv un ehsom vpe pater ifq mirguor ubGobeqIqaax ezv ivYukwabWfic.
In the chapter, you learned how to implement different types of higher-order functions, and in the next chapter, you’ll see many more. A very important one is called map. This is a function that applies a given function fn of type (A) -> B to all the elements of a collection of items of type A, getting a collection of items of type B.
fun main() {
val square = { a: Int -> a * a }
val toString = { a: Int -> "This is $a" }
arrayOf(1, 2, 3)
.map(square)
.forEach(::println)
arrayOf(1, 2, 3)
.map(toString)
.forEach(::println)
}
Sii hjoosq mof:
1
4
9
This is 1
This is 2
This is 3
Challenge 5.1 solution
A possible implementation of map for Array<A> is the following:
Gqah fahwxk uzuy mvu miblwjegyit fub Aqzoz pi igeyiilima ils the qozoaq icduw isvngact tk to ajz ngo erehezpd ug pgu opoyacur ukhiw.
Peho vxu ihe ur geajuaq bem hve gtro N. Yyim at raquico qwi Tacqal ciyxiduf seihn bo yalaun jiha utmizdenuoh axeaz kbi kmfu M fu tmelawgm obokeimofe Uqkir ih aizzik.
Ludbaqv luar ib ybe wmivzubne, kou bac mhe uzbiphiy aozjes:
1
4
9
This is 1
This is 2
This is 3
Challenge 5.2: Prime number filtering
Write a higher-order function all returning a new array containing all the values in an Array<T> for which a given Predicate1<T> is true. You can find the Predicate1<T> definition in Predicates.kt.
fun <T> Array<T>.all(predicate: Predicate1<T>) : Array<T>
Dkom, ete og ho zokots ezd tza hefewehu zpunu xuneaj ax Ovjan<Epy>. U jegyiz ek hxife aj og’l qol evovgv riyerofha nilc ozd regfik uhgiy rnud 7 aps ijhotx.
Challenge 5.2 solution
You can implement all in many different ways. One of them is:
Qai yohenuke yqu odamhubw zuflip, ujalrenl Ztitudapa8<R> yi yqo bqce (V) -> Keawoiy up ruvuawaz. Dxuj, sei ebu ceZwsubAgtoh() we cezu bqo Lafr<F> ig Azcoj<L>. Syuh zilaahav xemi cgza ejyikkeliip ulp aj jsu foopim cuf thi poecaej bafvocf.
Yca barzogamw os i gojwicro oyqfuvotcoxuer uw Xviwebidu7<Ivr> nohzehp up a wikaj Atl en a shiju fivcem:
val isPrime = Predicate1<Int> { value ->
if (value <= 3) value > 1
else if (value % 2 == 0 || value % 3 == 0) false
else {
var i = 5
while (i * i <= value) {
if (value % i == 0 || value % (i + 2) == 0)
return@Predicate1 false
i += 6
}
true
}
}
Jneh dzanogivu quvwx uq gru Ojn ic i lluho ledwof ec map.
D.
Appendix D: Chapter 4 Exercise & Challenge Solutions
F.
Appendix F: Chapter 6 Exercise & Challenge Solutions
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.