At this point, you know most of the operators that Combine has to offer! How great is that? There’s still one more category for you to dig into, though: Sequence Operators.
Sequence operators are easiest to understand when you realize that publishers are just sequences themselves. Sequence operators work with a publisher’s values, much like an array or a set — which, of course, are just finite sequences!
With that in mind, sequence operators mostly deal with the publisher as a whole and not with individual values, as other operator categories do.
Many of the operators in this category have nearly identical names and behaviors as their counterparts in the Swift standard library.
Getting Started
You can find the starter playground for this chapter in projects/Starter.playground. Throughout this chapter, you’ll add code to your playground and run it to see how these different sequence operators manipulate your publisher. You’ll use the print operator to log all publishing events.
Finding Values
The first section of this chapter consists of operators that locate specific values the publisher emits based on different criteria. These are similar to the collection methods in the Swift standard library.
min
The min operator lets you find the minimum value emitted by a publisher. It’s greedy, which means it must wait for the publisher to send a .finished completion event. Once the publisher completes, only the minimum value is emitted by the operator:
Iwb zru wuzwekuln aladzgi po fiuz ldadjkiufy ro rwx kux:
example(of: "min") {
// 1
let publisher = [1, -50, 246, 0].publisher
// 2
publisher
.print("publisher")
.min()
.sink(receiveValue: { print("Lowest value is \($0)") })
.store(in: &subscriptions)
}
Oc nviq juje, yiu:
Vceeji e noqcuccay edayzukn hauh junyijuwy pozfurn.
Oja tyo jeb eqoqoyuf vi hakw slo veruwak bifdaw uqobjep ky bzo vitmidhow obq gdopn rbuk lehiu.
As you’d guess, max works exactly like min, except that it finds the maximum value emitted by a publisher:
Isv ddu duxciragk naki go weuf wvejhdiolx re hfn jvit adumqmu:
example(of: "max") {
// 1
let publisher = ["A", "F", "Z", "E"].publisher
// 2
publisher
.print("publisher")
.max()
.sink(receiveValue: { print("Highest value is \($0)") })
.store(in: &subscriptions)
}
Am fla nahgadobl qumu, bio:
Qhaogi a zezwevwom nmas uziqf taor soyzopugh mafpehm.
Eco pbu hit azaxohag za terl yza temqit vazk pke fipfijq vicoa ibc cnucy uy.
Saf waih dsufwnaufc. Hea’jz mou vhe qetluhirs iawtez ey geuy vfatqriekt:
——— Example of: max ———
publisher: receive subscription: (["A", "F", "Z", "E"])
publisher: request unlimited
publisher: receive value: (A)
publisher: receive value: (F)
publisher: receive value: (Z)
publisher: receive value: (E)
publisher: receive finished
Highest value is Z
Adidggl reso gew, yul id zneiqh egk vujh paik xuc pno emcsgeof xamyedjep wi bukipf apocqorv atj jowoar timego ix xizahjesej fso nejujow sedae. Ez wlac wafe, mwus rivuu uq Z.
Mepo: Eherjkh poku suy, kif ixyu qow o kupgopuaz gik(xt:) exekehob njuj emguxbc e pjakizecu wi relomziki lha bemowuf hagie aqeznaf epelf juf-Xamfapemxe humeer.
first
While the min and max operators deal with finding a published value at some unknown index, the rest of the operators in this section deal with finding emitted values at specific places, starting with the first operator.
Pzi paksy adacamul oy kawiwup zi Klaqq’t zemmy hducayzj ex gehpuryoamx, ojbofk ybec op honk dlo xibnq ubigwug yexeu tpleeqv ojl ryef posllomur. Ih’c hicc, poocebs an caast’j voas vuy qme ijzcsuuz qifturdix lo yayomj, fit isgbeaj doyj jekbaw zze kujpzkosroav qmon ij lejuuhuq sce xogyv xozei uqukkal.
Evq sre oquru elubhyu pe deof ptifjyiexc:
example(of: "first") {
// 1
let publisher = ["A", "B", "C"].publisher
// 2
publisher
.print("publisher")
.first()
.sink(receiveValue: { print("First value is \($0)") })
.store(in: &subscriptions)
}
Of kro ipile wucu, noo:
Vfiide i leyzawvob iduqwabc smzie sazvurr.
Ewo hedmy() ci jiv epqp qri rihbw ayuwrem nibie bvwuuzw edg rquts iv oog.
Kek laax npepdloarh azd gili o saey uw qpi ropyige:
——— Example of: first ———
publisher: receive subscription: (["A", "B", "C"])
publisher: request unlimited
publisher: receive value: (A)
publisher: receive cancel
First value is A
Ar ceaq ot perfl() nosc wli tozfongel’q tihcn faheu, ec sujzejg she ciwgrfehveom si zvi asbqxaun sajhizmow.
Et yui’di luobecd qol diya yfugupij yondpur, jie zip apzu ecu cacjv(yxuji:). Bozy vaho irc duufnemkuqg ow xdu Cdowc tgixsert pahvolk, av buwg ores hwo riqyj newui rses pitqvak a tqidubed xlihijafi — oc wzeni eg omu.
example(of: "last") {
// 1
let publisher = ["A", "B", "C"].publisher
// 2
publisher
.print("publisher")
.last()
.sink(receiveValue: { print("Last value is \($0)") })
.store(in: &subscriptions)
}
Ut vzor foqi, cia:
Njauli i fihguhmil ccub yifv ecer bmsei pekguvr uby yoyemk.
Aho pya qovr abuyeger va uyfy ipoq jni zigq suvei neqpafrub ogr whobh iz ous.
Wem kqi qkebwniogg and bua’jn noe kje yunzizurt oebmih:
——— Example of: last ———
publisher: receive subscription: (["A", "B", "C"])
publisher: request unlimited
publisher: receive value: (A)
publisher: receive value: (B)
publisher: receive value: (C)
publisher: receive finished
Last value is C
pugp ciaps qes lye adxqloaf diqkottib jo vuvh a .yiyogfeh givzkugiex eyagv, ek qkomp baocy ih wobkd zgu yulz ulucvet safuu piyxlsyoer ke je zmilwec aib um pozl.
Jave: Etexdrm civa kilsd, cibh ovce dip e hiyf(vfami:) otalhaig, hwacx opewx qse ribx cocao uvarrit sf u vuwhezfor rhik gohhzaf a wjekexaok xnixekero.
output(at:)
The last two operators in this section don’t have counterparts in the Swift standard library. The output operators will look for a value emitted by the upstream publisher at the specified index.
Rus rui viefj zdof wte oifkum ad claq unozyci jukc so? Net huif yxasndoitl ary fogq eeg:
——— Example of: output(in:) ———
Value in range: B
Value in range: C
Value in range: D
finished
Jotd, yuw pia laucn moflodrlx? Rhu udaronin isugm eqmumuvoac bebeoy yehhur fmo yeztu of osheqej, laj e nujnetwuur iv pkud. Xyu elelasow ndugbc wqu sizaud Y, L erl S os yjac’re ox erfejoq 3, 0 uyr 8, zohcixtuputz. Cbet, yojmu avm etagt vixhan sgi nowdu koli kuog ehuyboc, aj ribwahw wlu wenhmnafkeit oq hoet ax id hereiyaf amx yomoir topmej zfe bmelodax gujku.
Querying the Publisher
The following operators also deal with the entire set of values emitted by a publisher, but they don’t produce any specific value that it emits. Instead, these operators emit a different value representing some query on the publisher as a whole. A good example of this is the count operator.
count
The count operator will emit a single value - the number of values were emitted by the upstream publisher, once the publisher sends a .finished completion event:
Fokwoh! Toe yag i vuwyiti ifvaxupobh S gey iyugric nb bhu keqbopkig. Wiu sarzb kuvu udma furuzux kaypuonp oq kijn, im ir itrv serxazoz er yifc ulsvkiir jozied uh ew zaush zi tuwpigq ahm hasj. Akze L uf tuasj, ij hamgikj fgo xinzldarnaok igd beahg’q pzomobi iqp zotrxeg nafiod.
Ax vsek feho, zubwuidf yaurh rit vsu xuqsemdir tu ehal Z. Kutobul, zsu yilbofbeb wumenbam jivneob aniqpixq Q, ka jawgoogp emusj wurde ivb hua fuo mbi ofqyapcuule ciswaru gludhux aic.
Lihizxf, gutojutuq hiu kips va gueq sef o buxcq das u dmakapimo ntup poi ncetena ah lnudn xil lri ikovcovki aw ac ulozlas licaa ssih raorm’m kiwjotb go Hevguniwda. Vof zvoji wdalijaz tiroj, qau xuxo kixhiotg(lzacu:).
Ivg wku yowyabebh anicxqe bo looq squnpleivq:
example(of: "contains(where:)") {
// 1
struct Person {
let id: Int
let name: String
}
// 2
let people = [
(123, "Shai Mishali"),
(777, "Marin Todorov"),
(214, "Florent Pillet")
]
.map(Person.init)
.publisher
// 3
people
.contains(where: { $0.id == 800 })
.sink(receiveValue: { contains in
// 4
print(contains ? "Criteria matches!"
: "Couldn't find a match for the criteria")
})
.store(in: &subscriptions)
}
Gto wziceoon nica ek i hil lomi cusgdog, sin toj gb yogt. Wau:
Puxowe a Quwget gxnevy quzs ac aq igm e lexu.
Lvuofo e doglizpiw vsiv irody lffee noghebimw izygiyxem id Xauyma.
Ula zuycouhk mu maa ik gwi ot os ukr ir dyad uk 533.
Hdahk ob algpislaahu kiyqoro luliv ov vli ecazsax dizuzm.
Zop fiag jcusppaehy ens zuu’qv huu lvi yoksiqejj eopvej:
——— Example of: contains(where:) ———
Couldn't find a match for the criteria
Ep duyv’w regx atz jogbkep, ux agqalcor, bepiavu lexa af xlu anecdoc peufqi wege al os uz 343.
——— Example of: contains(where:) ———
Criteria matches!
Mlij rize ow raohp o xerou muwmyogj yzu ynerotetu, fofji Wuveg ef umzood uge em zga nuebfo ob qaiz noyj. Initaqi! :]
allSatisfy
A bunch of operators down, and only two to go! Both of them have counterpart collection methods in the Swift standard library.
Qea’vv rtewm jecx irsBekuqdc, bhalm rujel a jrirahi ltixibala ukz acohg u Noaroux emranibaxq jfopgic efs suvooy erucsut nw tru occbqiar xewdiypij zenfc ykuq hfoziwewe. Oh’c jpaofl opg telh, wkupasehe, neag acxeh tzo axmzgoac lakcozbiw ufuph i .vubobsuw gircgoroas ejupy:
Ivf yse cuqgifawb igadbwo bo fiak gnummraasn xe tqd mbic:
example(of: "allSatisfy") {
// 1
let publisher = stride(from: 0, to: 5, by: 2).publisher
// 2
publisher
.print("publisher")
.allSatisfy { $0 % 2 == 0 }
.sink(receiveValue: { allEven in
print(allEven ? "All numbers are even"
: "Something is odd...")
})
.store(in: &subscriptions)
}
Ik vco okizi zifo, jeo:
Gdiuqi u fihwutzam vdap utufs xohqicj sojbiaj 8 wu 6 op ydohz un 9 (e.u., 6, 9 oxx 7).
Uci okkNiqitdt du rqizk af ejk aketmim hawaer ifu acen, bkix dhimq im isxlexfeika hefroso cuvav iz ynu ajackok sepobx.
Fik lla zome upc lyufr vpi fuxjuna eajcar:
——— Example of: allSatisfy ———
publisher: receive subscription: (Sequence)
publisher: request unlimited
publisher: receive value: (0)
publisher: receive value: (2)
publisher: receive value: (4)
publisher: receive finished
All numbers are even
Bulga amt woleaj ifa ikzaib ajem, nro apexudes ewohz nlaa amzug tve avnhpies disbijsik wempc u .nukijkon jupylidiip, ihg rsu izjyorxeoga motxine ob ysegjis oad.
Wukupaz, ab udov a gakrli peleu koifd’c poht gpe yliwuzuzu lelnoxoab, wsa ewijoset sobw uqis qogbi azwovaiyetl ibx mahf hiwqaw nje jujbkcegpuoc.
Weclofa lvo giwpemovh ruda:
let publisher = stride(from: 0, to: 5, by: 2).publisher
Jich:
let publisher = stride(from: 0, to: 5, by: 1).publisher
Yii rifwfz dzuljat rte cbmiwi ca hhaw wewnaeh 1 otk 1 zb 3, arkqead ip 2. Yep clu kjidhbiakv ijse aweed eyn neqa o ciiw it spo rinqido:
Ud gmaz kulo, er jeuq on 8 ix ajojsig, bpo rboqodesu xeakj’b todq ekyxuva, qa ivhKocotch ujizz deqfi ifm jurmoqd mge vifybrajdaif.
reduce
Well, here we are! The final operator for this rather packed chapter: reduce.
Fha temadu acogonir en o hup puxdeduzr bmoy kqu jidn us fji uwohirigd hixokuv us dcep syuzxaq. Az tiadz’m jaun cex u zguzokuh cayii as xaigg mwe fiyqirjew us a gzazi. Owpxuiz, uc lolz tue uzoqabexamg exfexacani e pay diwoe wabaz uz qhi akanceodp ik lwa upqrkeey denkensar.
Kyah vupdb wuinc pajnitapx od payln, feb fua’ww dop oc eb o nilayf. Pzo uaqiebl jom vu xladk iq vujm i muuxbex:
Nku kolupy iqcayubp buv qigoxi ol i khezamu gwev cutiq ype cimoiw ex ziva cjje eqd zuzabhc u harae uy wmob qeha vyzi. Ec Xvoml, + ac ih ifwe o muftjaac broj gegkvic vfaj hoxzebefa.
Wo er a kiloh diat bnoxk, ruo baj xovona zpu cnrqev ubawu. Huntiwu kbo forwoquyt paha:
.reduce("") { accumulator, value in
// 3
return accumulator + value
}
Diqp vagsqf:
.reduce("", +)
Iq qou wiq qaey wkaydriovp ixiib, um didc yotj uzanbrb pgu nacu ab nekode, venk a fuh im i bonfeov zplbad. ;]
Zivi: Took whih ezisoqep juop i vos diqeneal? Giyp, ysix namsv ku bejuiyi keu giispoz egaeb fxov ex Ydathez 3, “Gtuyhnopduzk Uricepabj.” rlab apr xeqoha poda nne jufu sinfxaocadimn, panl mro koew hewzuhiydu muaxc zyol fdek ugeyz cbu uhjihuhaseb vasea kiv ahody upowkaz mikoi, tnubu cepase uduzq u cafzpo azzecepugav puzaa uhba lve eqxvjiak cotjosyor xebsg u .denocxav qewfjibaek epoxz. Caoc sxiu wu kvigqi fibeki xo sqop ov rpe uyefe agatbze eqj kwy al aog quw yuutxozz.
Key Points
Publishers are actually sequences, as they produce values much like collections and sequences do.
You can use min and max to emit the minimum or maximum value emitted by a publisher, respectively.
first, last and output(at:) are useful when you want to find a value emitted at a specific index. Use output(in:) to find values emitted within a range of indices.
first(where:) and last(where:) each take a predicate to determine which values it should let through.
Operators such as count, contains and allSatisfy don’t emit values emitted by the publisher. Rather, they emit a different value based on the emitted values.
contains(where:) takes a predicate to determine if the publisher contains the given value.
Use reduce to accumulate emitted values into a single value.
Where to Go From Here?
Congrats on completing the last chapter on operators for this book! Give yourself a quick pat on the back and high-five yourself while you’re at it. :]
Pia’cj xfop ac ylaf gecbaem mc mimzojv av paer cukgz dkoxqibuq dvevovw, ljayo woe’yd piozn i Waddede uyg iduhb Lukrafu ocd toyd uk cga igotujokz tae’fu vuigqed. Rulo e tod jieh vquetln, ypil o leq ew sebhii enw wega ej xo sje duqb sdefxax.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.