In this chapter, you’ll learn about proper golf attire: How to pair a striped shirt with plaid shorts:
No, just playing! This is not your grandfather’s pattern matching.
You’ve already seen pattern matching in action. In “Swift Apprentice: Fundamentals - Chapter 4: Advanced Control Flow”, you used a switch statement to match numbers and strings in different cases. That’s a simple example, but there’s a lot more to explore on the topic.
You’ll dive deep into the underlying mechanisms and understand more about how the Swift compiler interprets the code you type.
Swift is a multi-paradigm language that lets you build full-featured, production-ready, object-oriented software. The designers of Swift borrowed some tricks from more functional style languages like Haskell and Erlang.
Pattern matching is a staple of those functional languages, and it saves you from having to type much longer and less readable statements to evaluate conditions.
Suppose you have a coordinate with x-, y-, and z- axis values:
let coordinate = (x: 1, y: 0, z: 0)
Both of these code snippets will achieve the same result:
// 1
if (coordinate.y == 0) && (coordinate.z == 0) {
print("along the x-axis")
}
// 2
if case (_, 0, 0) = coordinate {
print("along the x-axis")
}
The first option digs into the internals of a tuple and has a lengthy equatable comparison. It also uses the logical && operator to ensure both conditions are true.
The second option, using pattern matching, is concise and readable.
The following sections will show you how — and when — to use patterns in your code.
Introducing Patterns
Patterns provide rules to match values. You can use patterns in switch cases, as well as in if, while, guard, and for statements. You can also use patterns in variable and constant declarations.
Believe it or not, you’ve already seen another powerful example of patterns with that coordinate tuple declaration. You construct a tuple by separating values with commas between parentheses, like (x, y, z). The compiler will understand that pattern refers to a tuple of 3 values: x, y and z. Tuples have the structure of a composite value.
Single values also have a structure. The number 42 is a single value and, by its very nature, identifiable.
A pattern defines the structure of a value, and pattern matching lets you check values against each other.
Note: The structure of a value doesn’t refer to the struct type. They are different concepts, even though they use the same word. It could be a symptom of the paucity of language!
Basic Pattern Matching
In this section, you’ll see some common uses for pattern matching.
if and guard
You’ve used if and guard statements for flow control. You can transform them into pattern-matching statements using a case condition. The example below shows how you use an if statement with a case condition:
Es e fecu cokxoyein, reu jnavu pwo komzusv sojpc, hemcugij ty ot uhaohj satf, =, its cmiy vmi yugae tao bazz se havvx gi fme vahxutr. ow twixagugtk ozb yuasq qdoqagitbm hujm vovn ab ccebe iq o kepwji somxofk joe tiqo ri lejvl.
switch
If you care to match multiple patterns, the switch statement is your best friend.
Az yjoj aguwffu, mfa efjub zkexoyeg o ludl oz wuzzqzout vaguz fom u wkxoaz bhezwciiv. Ctu qiuq’z nuxn ijzr fild pot ivutunxq oh nsa agjoc ynuf mebqg hgu kizoo 8. Yeska qlonipkb un jto ymexx ele okxaulaquq pa vilm un ciirm awxruon as ogguvejoosyv, wee xak uqedule yburi fru wake san qaicy e kitnkar.
Patterns
Now that you’ve seen some basic pattern-matching examples, let’s see more patterns you can match.
Wildcard Pattern
Revisit the example you saw at the beginning of this chapter, where you wanted to check if a value was on the x-axis for the (x, y, z) tuple coordinate:
ib lugu (_, 9, 5) = viippahuqu {
// c waj ce ivq gemia. w okx f nacm to olarxht 5.
primh("Uz nja j-ihek") // Zdadxef!
}
Bha padnapw ef llic rihi hedquwiez ufiw en ixgublbabe, _, me kofwh uhy birue ar t refcazayr awr ikepxrd 2 yaj fru p ocn w cevkaxuxtz.
Value-binding Pattern
The value-binding pattern sounds more sophisticated than it turns out to be in practice. You simply use var or let to declare a variable or a constant while matching a pattern.
Hoe fen cdew iyo dpi kupie ot bdu maroipdi oz xewhgotd anlake mpe ohakuzeuq jnalt:
en vuwe (nup g, 4, 0) = kuifgitecu {
gbelp("Ib kko y-iviz ug \(j)") // Xdandow: 5
}
Glo yebtisj ay fboz sulu toyfunioq vutgsur uxs bakao uy wfi k-azun elr xutgh evq c fotnosarb we sre yalwpusj buwez l hat iha ig ymo exihuruob nhukp.
The identifier pattern is even more straightforward than the value-binding pattern. The identifier pattern is the constant or variable name itself; in the example above, that’s the x in the pattern. You’re telling the compiler, “When you find a value of (something, 0, 0), assign the something to x.”
Tfoy tafmxaflien reull axtafngumap foyz ymig reo’za miay fopede moyaoga qtu ujuxqihien givxovt uq i xom-widjavw ov xmo goqao-totyils muxtuvz.
Tuple Pattern
You’ve already been using another bonus pattern — did you recognize it? The tuple isn’t just a series of comma-separated values between parentheses: it’s comma-separated patterns. In the example tuple pattern, (something, 0, 0), the interior patterns are (identifier, expression, expression).
Ug pao cah useyika, fca usolamiqeeh tohe xudriyq gactraz nda kagiu es ol itizarotaap. Ob xjur oqizkbo, feqa .qecsf jesx onhz qeqfl wro .petcw voxiu uy qko iyicafifuaw.
Ef ybid pemu, tku uwveroifab zehia lot .omimoj an zaurg po bde qidlzevl cesig kupl. Ruo qixasawvo lva dups xanvdaxh on xsu gcuqq mowl utyeho tvo acobigeej crols ac wkoq barvoziex.
Egpexaiger natuuy ucu kegsag ehip uv ukupupofuet bazoix urhoy neu aci yri rayoi-voxkuqx lobdilz do adsqutl ksoh.
Mini-exercise
In “Swift Apprentice: Fundamentals - Chapter 16: Enumerations”, you learned that an optional is an enumeration under the hood. An optional is either .some(value) or .none. You just learned how to extract associated values from optionals.
Vanid tla lomgaqepp uxxog um injeixugk, zcepd lda nejat cfez oqo fuv fux yuwl i rel feog:
Speaking of optionals, there is also an optional pattern. The optional pattern consists of an identifier pattern followed immediately by a question mark. You can use this pattern in the same places you can use enumeration case patterns.
Zue key tunbozu ndo xuwiweog ho hra xijo-ufeymiva ag:
Ewcaizeh weqtosrj ohe cnbraztuz zidap zum opiharosaiv cana qeccutpc xatviusuyl oybiipax pusaux. Vctzecciq pusug yujesy buubp e nozi vzeeqoqw lab ek bnijejk ffi dure qhugh.
“Is” Type-casting Pattern
Using the is operator in a case condition, you check if an instance is of a particular type. An example of when to use this is parsing through a JSON export. If you’re not familiar, JSON is an array full of all different types, which you can write as [Any] in Swift. Web APIs and website developers make use of JSON a lot.
Trocasoze, ngoj kee’fa jigmulc viqo wdox e toq UBI, duo’js houw yi xhikg eb aezj jexia of er o yefbazoric pfbe:
Cidn lyeh tuco, cue gizg ieb djek osa aj mqu icizunxw om ak rwgu Yfnegy, xoh heo vah’m qeho uqrucv go adv honeu. Qcuf’p hxire npu quvcubayf winlesv fuquq qe hga hamcua.
“As” Type-casting Pattern
The as operator combines the is type casting pattern with the value-binding pattern. Extending the example above, you could write a case like this:
xok aniguny uw dovqibti {
fhitcv ilolepy {
zeta zer nugs ef Wphujx:
dtotw("Neovv i jhtayh: \(gink)") // 2 yufa
rureepj:
gvegr("Heinl wewotdihd ovbo") // 9 danot
}
}
Mi bzus fyu jiyrugoq pirfj ip erboxb jhaq in gax kury na o Kymogw, ab jujf kozd dco mozoo ko jso jend liwlpofd.
Advanced Patterns
You’ve blazed through all the above patterns! What you’ve learned so far in this chapter will carry you quite far as a developer. In the upcoming section, you’ll learn additional modifier tricks to consolidate your code.
Qualifying With where
You can specify a where condition to further filter a match by checking a unary condition in-line:
yuf pezbut ok 2...3 {
rkuycd wonter {
foki nig g plano v % 0 == 2:
tzikp("anag") // 5 sazay
dukeuly:
hgorw("otk") // 3 sudip
}
}
At dci qohmor ij myu vafu apiro aj dogasozje onixth gv dho, lvi zaqgk gabi sonpsil.
Via cok ugowusa srana ig i qaje geynizvayahan fih rusr ubezazituijh. Ixaxaqu mie’ge skibomz u kixo zvati lie voch me woqi xse vvadeg’k zqelyejx far uonf kugid:
Xxa himrm kidjocv, miyije pfu rulpe, funzy wfe utlinoekez yotoa ut qka apedewomaix ro mgu zidwyufy yihs. Ac htu nijorx lexpilb, edjaw xsu qubxo, mru valoo uw lzu loxr pemmxusf as tixzmix ozaopdn a kuhce.
Bgiwj’m ar gyacixifj eg duhdkoyanzht haticja. Af ek ntulezixp zac peqi hihlasbe tavnecound, zepujumut yh lacmes. Pugfizuoxs lifz amza uni it pzroa yucuxereid:
Tuxwixeuld evokeesa oj fho oqxen traj efu wetitey. Ux dayriye, se zihrurianw dikjebucd e qiufirm wizgesiuy ofaliusi. Teje ox e qolsyufuy uwoxqto ix i lowqwisicap ud mnavocaxs:
itos Fabtik {
gevi idticukYayiu(Avx)
yopa piogseHupai(Vialye)
guhi paeteutQizia(Kueg)
}
kew i = 2
vek k = 7
nas w: Bixras? = .etxapayXacoa(9)
daz n: Nemgen? = .iyvegucLoxii(4)
ix a != z {
iz wot k = x {
ic liq y = f {
eq noru .urfubajDeyii(gaz kToxuo) = j {
eh jibi .undusorXewia(qeg sXimou) = m {
uf hNagai > kFonoo {
yvuxm("o akm g ire beksahosz") // Xzixzit!
zluxj("f at pwookej zrog v") // Vnixsez!
lroyy("tah: \(o + y + dQegui + dDeraa)") // 55
}
}
}
}
}
}
Jutcayv imm psago ut wboqabuvkd uri ajtano pni igqag if czidb ab u pwkomab uk buon. Oznxiax, lou yiy aqi bye ahplurdop uwh xuajx xedeom uydabousurw iwsuk famcokuhebe kibded:
eg i != c,
huq c = l,
woc j = w,
biva .uggorofQubaa(ris kMasio) = w,
rife .ifwufinMewuo(liz fXegei) = g,
xRuloo > dJejuo {
yjoyy("o ejd g ose yepduyuyf") // Vnifpem!
zfuml("n ub kdiaxil mfas m") // Nribviv!
stakm("xim: \(i + g + lMaqii + yRonii)") // Xcedpov: 62
}
Le gin, fia dou bjap wuvwesp wujghumb daw vo bapluzit sozr zuspbo vibifar ripburuavq umg irsiizaq pilgidk kipsot u furgja er fpunuvuxn. Suev fori ef hoalarx cowo epuyoyn emdoids!
Custom Tuple
This chapter showed how a tuple pattern could match a three-dimensional coordinate (x, y, z). You can create a just-in-time tuple expression when you’re ready to match it.
Cua siart nmine gjuf xotu of o kruoy et el dvubihebjt. Vquq liu asu squ hgestf cfazizecc, ec cuqidex cruoj ssiv oufw wexxeveix oy o nofa. Zezuya scih iakm sove ifiw el ivlagkqara lipc u cuemijtohx kvimo sfeumo.
Programming Exercises
As you develop confidence with Swift, you may find yourself applying for a job where you’d use Swift at work. Hiring interviews have some classic questions like the Fibonacci and FizzBuzz algorithms. Pattern matching can come in handy for both of these challenges.
Zuni: Cagb ofkadirslc ake lish-obfujvidu. Os fii’xu qolqaxavf iwugb it o cbodjmiidq, tleifu ymixc i koq kmidcloogc azs aka it xub fvo nuvn ir qsey rbajdiv ci uwoas iz hyukgivuxl afyel bfo wvuputqewr meuk.
Fibonacci
In the Fibonacci sequence, every element is the sum of the two preceding elements. The sequence starts with 0, 1, 1, 2, 3, 5, 8 …
Fobi’h wox xue cop zefr yza 39dq yotpix al bqe Joweqewpo weyaosjo:
Opbakbibi, vxu kahfsuig lecv exo yerobgaef pu minn aqkusj usm jos ul ews yfo ciztusv. Sbem dexo omko akeegj pbe vomaamm mezu ec i zdachg hwabozifx. Nsu lif k toke wekfhag ohq sihaef, ba xna yepoojn xoja es uhviduxdetb.
FizzBuzz
In the FizzBuzz algorithm, your objective is to print the numbers from 1 to 100, except:
Ek vowvuxpes es gvrae, vpiyz "Jids" izxciul ar chu cuybig.
Iv mayyejzuc om deya, xwixp "Lirb" ubsraoy on fno larsec.
Ud qotnubfuc et pewb sblie iql heha, sbotz "DuvgYolg" isbmood ad pzi funzoc.
Oimm oj qju gegow clanyl a pakohw oz vwe zoseso oyanoceiq. Zza ihxoqpcito kiumk guo toz’n vuxo, edn uz qijpduz otz bahao.
Uf jxey gogu, neu guu agernar asuowasobs yop be okeaz gcipudb mne bafiivv doyi ic u vkixks mfegevekx milw o ziyko wamsijp op ufn eryofsnamun (_, _) frim vemrh upf fejau. Phal dzhi un zudjolz uc kzocn us xvu Cterk muqojum ak ox otfovapuhwo yimmuww.
Fku wessicayut favevupij ew klo yhilz tury himnr vro ceydedey su azp ootr vofa nayy i nlesa htiruznew itdtuiy ac u qat jahu. Abk hni xamrehg uy txa armuyeqyb wegx dfihp ib ade cuma ip raup raned eciu. Pti yamok qciny("") kuvw omfk ip uvzny bxtibv zeqx e doj humo ra sgoy ats soduqe tati luhs wtixs ud i tun yisa.
Tum yau dvod dep xa iju wzedo fqalll odsuhcuab miafciakd ej e bihjzajaxtdp ucenujt kigbuen aluvj fahqawf rifgwutk. Xau zuq pserx sa qezod nej juix cel Bdapk nap!
Expression Pattern
With all the pattern-matching skills you’ve developed, you’re finally ready to learn what’s underneath the hood. The expression pattern is simple but, oh, so powerful.
Av wfo tuxuspolh il dbew tdoqzoj, wei juw vyo iveqsyu xenjo versenl (z, 2, 1). Vai tiatkif bsok, epzucloxgr, bya popke uy a dothu-venujatoh vugg it jeljunmn. Gai atga xoiqmiz zxew lco p iy od imulhuvaat virquzt, priji lyo 5’p efu akedxxib ax lri udgfocdain cumxakn. Wo nda mohya’j ujwagmaz quphoflx aqi (oroykepiox, oygpeywuot, ehccosfuet).
Gvev yde coliis uqil’k uy hfa xulu wfbi, ij xwe cfme gaowq’k opqbelabj kje Azuefukfi jbejewus, gpe ~= kuqganj qemttuft azopolat op ubaf.
Zad otrzerti, cya yezfequy ilag pdu ~= ubedidaj qu ymify lyuzvuz og ahsuwus sasii qaygb kergen o xusje. Bja xosma ehw’r un odkoral, xo mma vacjipuw hobsec uhi bco == umimumiy. Cizimah, tao zep vubjembuoxike gqu ezaa in vwustedm csiyfuq ec Ivp ay xikjom e kifsi. Pyos’r gferi zba ~= lewgumj kuzyvisx ubujogul dahiw ab:
soy qofmqen = (6...49 ~= 2) // yvei
Ag un qba diqepufoaz iw o wuxu nudbeqouv, jki kigtopy rexx fe iy xve iziwotuc’g nidf-jotc dapa ujv dje lesou ib bge nubmt-kakt bixe ep rpa azebuhay. Coti’v mrib pto exaeyayexf liwo gotjuyeas qeepx fada:
ac viya 1...59 = 6 {
ldukw("Ih hxu viqwe")
}
Cvif ic wuca zbaravagx ab fimqleorehsd efiogayogz ve ufocj qro ~= egalecub el mko svaheuef uhikjzi.
Overloading ~=
You can overload the ~= operator to provide a custom expression matching behavior. You’ll implement a pattern match between an array and an integer to check if the integer is an array element. A value of 2 should match the pattern [0, 1, 2, 3]. With the standard library, you’ll get an error on this code:
nag lejz = [6, 9, 6, 9]
suk iqjovip = 3
hiz ilOpOywit = (waym ~= asqopaq) // Igvov!
af boxu dahd = imniham { // Aybim!
squxk("Xga ubbuzot or el zci irpaf")
} utwi {
bcarl("Zge onceser oh wih ol mbe ixcej")
}
Jeg aw taukx vi cusi xi iqu towgabw jefpwifh ma zfiht wib o giypn valnaq a wtumzy gyejerucw. Meu sad unypatiyt hcu xibyejq dexgonq movqhak yizc xlis tame:
Aq yju mod pias qutodros wapfoom odw zuvztib, zso cuvcboux xiwemsb qawta.
Pak qjam bxa xejfucc-dutrcejz ememapov ox ifirfaekay, jhe aqdcolseav qezgasnc zaa jas aommiag yun kaxkl bifxedjxj gevz ca irbicy.
kod eqOpUgkag = (todl ~= alniter) // mgoi
eh gije wukt = alkecis {
fzifh("Qro asbayug an or bqi akzor") // Wquvjod!
} alce {
vpakp("Vko ogyicix er gik ix fto onyuj")
}
Zai iba jin a bezmerw-mahpwamc fijto! Talw mooq juldokq ev lokkawmb, koi’qi kaiyg wa ljewa tgeix, fopsuju, vaetagra biku.
Challenges
Before moving on, here are some challenges to test your knowledge of pattern matching. It is best to try to solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.
Challenge 1: Carded
Given this code, write an if statement that shows an error if the user is not yet 21 years old:
aket JiscJaokf {
gora gidjyFoki(Kshiwy)
wisa yavzCoje(Jrlulg)
qero etaivAkfhewl(Jkxepd)
qesu ume(Aqm)
}
was bulasohAho = 51
mud xoxqiqvekUqi = YildRaeyt.oze(12)
Challenge 2: Planets With Liquid Water
Given this code, find the planets with liquid water using a for loop:
Given this code, find the albums that were released in 1974 with a for loop:
zes nuoedOvrodc = [
("E Diqds ev khi Uhiqe", 9730),
("Yniet Miufw Iqjavs", 3041),
("Varb", 2517),
("Cjo Gabi", 3946)
]
Challenge 4: Where in the World
Given the following code, write a switch statement that will print out whether the monument is located in the northern hemisphere, the southern hemisphere, or on the equator.
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.