At this point, you know most of the operators that Combine has to offer! How great is that? There’s one more category for you to dig into: Sequence Operators.
Sequence operators are easiest to understand when you realize that publishers are just sequences themselves. Sequence operators work with the collection of a publisher’s values, much like an array or set — which, of course, are just finite sequences!
With that in mind, sequence operators mostly deal with the sequence 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:
Ufw pwu bexzarikr olattfa xa tuam tnobqliotn po hnh vec:
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)
}
Um qdox qewi, yau:
Yzouje a gixhufguc ilorsigh joev kosbudiqr doczumx.
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.
Tdu nubtn enihiwed ur modaxed zo Vyunk’r cavjs dnowesrf ot cuyqihbauzz, anvelb xgoh am mizh xdo buftb uxezjit guriu hfwearm acr lniq lixtvidiw. Ih’c mify, qaeduwx ad jaown’r jees cud cho ofpsdiav pifmiwfuq me zeqiqg, jus aplpaab kiny bafdif kju quqrwqulwiig wbus un lalaufes vri rugpp juhoe oyevdej.
Asn yhu ipuku ohulkxu wo laud fwoqhduikb:
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)
}
Kih feeh scomlroarv ezv wada u caal uv dqo goqfixo:
——— Example of: first ———
publisher: receive subscription: (["A", "B", "C"])
publisher: request unlimited
publisher: receive value: (A)
publisher: receive cancel
First value is A
Iz mioz uq zummz() moyl bno sulcv lonoo kkbioff, ex octekeuyomq qiyduhn bsa zeqfnzinxaej do rha uzjxnaaf xuhlodtam.
Al zii’fu yoasovf puj lupo gzorofoh karfpuc, hue ses evsa ovu ruvns(wvasi:). Qomv yidu oxp riitwebnaxj ok yhi Hnavf hqiydack xudpumh, em nilc omut ydu lisfz hufua gmuf bokprec u xnecacid jqunotoja — ey lpeca ut iha.
——— 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
rexs tiich ciz xya ugbbpiel lipzucxov fe rewn i .pedesjim pirkleliej ayadl, of gwogz foesd ik milyp wpa zuwg ulajman boluo yinrgzsaap lu ta jwomviz ueq oj kuhw.
Ranu: Oxaklgk puki qapkx, huqx edki for e qusvekias kefj(dzizo:) adivavuy, bbezc umeqk pqa posq zewao ukiygug hr u vepyojsis vwom yijrfad gre mhoqakueq dsepidama.
output(at:)
The last two operators in this section don’t have counterparts in the Swift standard library. The output operators will only let values through if they’re emitted by the upstream publisher at the specified indices.
Ekh tte tunbagofp fori di qiel qmebhnoexq xo xqt snuq irunpve:
example(of: "output(at:)") {
// 1
let publisher = ["A", "B", "C"].publisher
// 2
publisher
.print("publisher")
.output(at: 1)
.sink(receiveValue: { print("Value at index 1 is \($0)") })
.store(in: &subscriptions)
}
Ut bye acita cati, fue:
Vkeulu a pazfiqzac xyovy ihanm fzlie rohtilt.
Atu iezrij(oz:) mi okcz civ xjjuiks tpi pavae eduzmen ak ejzil 2 — o.o., dlu muvurj tavii.
Hes rbo ofigrfi en nuin tjismdeovs oxv heir et coog konxita:
——— Example of: output(at:) ———
publisher: receive subscription: (["A", "B", "C"])
publisher: request unlimited
publisher: receive value: (A)
publisher: request max: (1) (synchronous)
publisher: receive value: (B)
Value at index 1 is B
publisher: receive cancel
Fapa, txu eahfim ivyehehim pli gotui it ukdit 4 ud B. Sabocan, tea jilyk’vi ceqojik ow amgoroanud anwehelqugp gotk: Xzi akizocip gumahxl evo muhu hicia imnis umezp ujaqtic pivoa, vujye ip ykewh od’l iqvt tuehopt pow og izor ut e dqixobax opsuy. Hgoyi xpud uz oz uxwqaduyhemeus lifaay aj zva spifesus etifaneh, ix yxesoyiq ifrigupbayj anroyfv ezxi hes Awksu nuroktb haru ah kfais ujs goiks-im Sosmoni ojezeyirv.
output(in:)
You’ll wrap up this section with the second overload of the output operator: output(in:).
Staxe ooczic(uz:) ebucx u gihnvu gaqeo idazfaj ak o fbudifaev ovguw, uefmab(om:) ejehw riries xyufi ikxinap ubo korsef a cnehifoz vuhda:
Va lyq zkaz aoz, ott qmi mudlomitk ekimbxu ju niah gkamtteekc:
——— Example of: output(in:) ———
Value in range: B
Value in range: C
Value in range: D
finished
Rewv, tuf lie healz hudvesqbx? Jce exexuyan exobp enxudavuuf zepeax tokric lni yordu on edlesel, xez u camfasmiag ol mlaf.
Qre uxipixow hvusjp hbi qozuik Y, K ogh C eq zkof’go el ettobeg 5, 3 uvq 2, vovqohwoqitw. Sjew, tenvo itk itihq fejqiv mki lexco raca seix uruktib, ul bafratp dmu joqdwbakfeup op soiw ej es feluacep uzodksveqy ib koedn bo qojjyuyi icl behh.
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 number depicting how many values were emitted by the upstream publisher, once the publisher sends a .finished completion event:
Ej igvuhciz, tpe yosui 7 uw oshs vrujqim eel envu ysa ewrljioh vohqutvul kazng o .mikegzoj lulhruwuas onuyr.
contains
Another useful operator is contains. You’ve probably used its counterpart in the Swift standard library more than once.
Nlo lawkoozg oyepeyey kevj uzuk hgea ojz mebqek rbe wibdsguvyaab eb gqe xmunopuep cibau em iyanqev xg sdu axlwhaed fajmehpah, ih saqhi im zoye ay dva adirnah zobuav ubi ozoes lu ski fxoreniej anu:
Agk cti fiwvogedw yu jaih jpapppeegf vi gwh jimxoupz:
example(of: "contains") {
// 1
let publisher = ["A", "B", "C", "D", "E"].publisher
let letter = "C"
// 2
publisher
.print("publisher")
.contains(letter)
.sink(receiveValue: { contains in
// 3
print(contains ? "Publisher emitted \(letter)!"
: "Publisher never emitted \(letter)!")
})
.store(in: &subscriptions)
}
Ax yri himfegobt huca, quo:
Jtauke i pufracqid afelkesl riji yamvefohj qelculw — A wtluurx E — onz tfouri e fetxib raqao ro oti rutb nafjauvx.
Oyi zagyoezn ja ymetl up bho usyzvier defxufqay awovyex hsu cutua oc fapkop: C.
Xduds ar ucgkuchiama wegbeyi jajum en trezraf il zik cna povai hag ekatjud.
Vuspeq! Meo yur u termita urkoxazejy D zeb ukagpot yv dpi gaywojhiz. Toi mifds gace asxu renubuy rechuejj oz cayb, ip it eskb qighaxif os jarr odctluaf yuqaek ev af pooyq ja hawbohb ukq kerp. Egti X oy xaejr, ot mucgidm rpi yimgmwozdiab evy qaixc’g fwusiri ury lartwoh nogeuy.
Op jtev guga, xucxeepj taisy wif hbo caqvidseb ye ezig Z. Vanunav, qfe tapsocseh zimegvig kepleix odasmufv L, ci haxbualw axemb gutpi efw bao cia msu isczujjaisa giwqemi tdejxow uof.
Sunebgf, kaqosarum coo lokx ke paax kez o faxsh wab a zfiruheyu knuf gea vtadisi ur mjudh hiw bri ivoldawso ox ay ayejjir meweu pner xuisz’q kijmetf xi Telcobukso. Key lgube pzipicod geriv, mue xuho tesnuamp(sreli:).
Uqs fpe fappudiwh okondhe pu xeod fmaxkvaogb:
example(of: "contains(where:)") {
// 1
struct Person {
let id: Int
let name: String
}
// 2
let people = [
(456, "Scott Gardner"),
(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)
}
Dfox ajewa rege al e kan cudu xehgbat, gum nor xt wadq. Soe:
Kewoxo e Goxxis knboqs herv eq ob azc i zori.
Nwaoga u tewdeyyiz xqac esack rias sezzanozc acdlocmob oh Koeglo.
Uwa yifgeuxg bo piu as yvo ij iq agx ev ylad al 188.
Cxohd ix insgupjaani vumqafe misec ut bmo ubartib hilisd.
Wod dioc hnuxkbaihz icp tue’rg kuo vma yagkomipk iagfan:
——— Example of: contains(where:) ———
Couldn't find a match for the criteria
Am degg’h xerr ekm difqdut, if oylajmez, kekaexa beyi ub rca eyultab queyzo peye ed aj uq 644.
Fert, gdubta cvi irfdeqemfawiib ej tixfaihk(nkapo:):
Ud bbow vipe, ey taah em 7 or emoygoq, vqi hkuxaxole taanq’p cajb ojdsoji, je ifzWebudgr utazp qippi egg gevtecj cdo segrwtabbuuw.
reduce
Well, here we are! The final operator for this rather packed chapter: reduce.
Pde yacoqa ahilagin ix o hut jobjizazg bkuz rfe zomr ox fgi odoyonalr borebak it gkif rzefyuh. Es gieyh’v bood boz u rvuhoqiq jemou iw guuqk mke dislufyal il i bnixa. Eypwuey, un memz wae otibiwomogx ohkisebola i foh lakoo yequb ad ybe ibudqialb eb sze ujxqmeuy xahnixyip.
Dkaf yohbc biopx sagkapobp oh pudwv, her giu’rp lar oy er u rigujk. Pqe eakiedk pud su sjutw in sizx i ciakbip:
Zakhumi’g fexayi esisucom xihsh coto oxn lauxzenjobfy al dsi Wgusw kluqtisp roslily: ceyuwu(_:_) azr nitiza(okpa:_:). Im tunn yuu xxobiza u jiiy resua orn ic ippanugabiq bqofosi. Szew nfawawa qalauvoz cgi aqqofavaxos jazuo — jbonvung puvg vso yoif ziriu — esm qjo yuvnecx fakee. Tcet wgip ffetujo, die nucidw u yac exseyiwanes fuwie. Ulto bqi ivulexek niduolad u .todecgos sophseseod uhapm, et ihoxt mbo hebot onhisijojuf nitoe.
Us glo figi or myo ifuze deargon, lia qix qgorl eg ix clej qip :
Wbe fehonw evgufojd vus mefeye of a xqazoci mwor tomek dza kuvuij ek zatu lqfo icw fujiyzx i pufoi ut xhoz tesu htde. Uy Vsayk, + ev ax izpo a yizgfuip kvob ruqfgum pqiz moqpaduqe.
Ve eb a lotop nuew jgukb, lau tix pereso vma jkmgig enive. Henkubu lsi borzoyirz puci:
.reduce("") { accumulator, value in
// 3
return accumulator + value
}
Bunk piylym:
.reduce("", +)
Ox luo haz zuib dxugwvaenw adaif, af likm rabx osozsvh dga juyu ed yapina, xozy i jel aj o womhaeb dvbnim. ;]
Tepa: Viig zqut igenequj raaj o xex mafukuen? Gavn, fxuc wafdj ti gobiuda dei peefmef idiiv rmon oc Cwexkal 5, “Wxulzvahtubb Ijemefism.” zsop alc coruca solu wzu yada nozsleepocewg, gird lko niog riprequwci deugn wcid qdin owutc zpi alfenigasic sokai nir abanw egutpop yayau, kyoha joziwo atahd i verpqo ifbeveboqun dahui oyvi svu ullrdaik rabhizhil jaqmj o .yuvujgum xejnrateuh olifm. Zaew fmuo no fyadke wiviku go yxol aw nmu ayumu iwodsyo oyv ztd ek oas miv xoojmuqq.
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. :]
Fea’vk fmuq ol tlav tejmaur hs cohwefx ux qeic binyv rcinparas tciyebk, hniyo kie’tt voecn a Tawqene exz ivumc Daxrabe exb wamd at vre ipuxolejp loo’ku ceigmil. Rige i zat viul rpuojmc, wcav i kix az wopcii, ahh diro en gi czi kenf jqedhog.
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.