skrevet af Reinder de Vries den 9. juli 2020 i appudvikling, hurtig
i hurtig bruger du map()
, reduce()
og filter()
til at sløjfe over samlinger som arrays og ordbøger uden at bruge en for-loop.
funktionerne kort, Reducer og filtrer kommer fra området for funktionel programmering (FP). De kaldes højere ordensfunktioner, fordi de tager funktioner som input. Du anvender en funktion på et array, for eksempel for at transformere dets data.
hurtig ‘ s kort, reducere og filtrere funktioner kan udfordrende at pakke dit hoved rundt. Især hvis du altid har kodet for in
sløjfer for at løse iterationsproblemer. I denne vejledning lærer du, hvordan du bruger funktionerne map(_:)
, reduce(_:_:)
og filter(_:)
i hurtig.
lad os komme i gang!
- Introduktion til kort, Reducer og filtrer
- Hurtig Start: Funktioner i højere orden i hurtig
- brug af kortfunktionen
- brug af Reducer-funktionen
- brug af Filterfunktionen
- kombination af kort, Reducer og filtrer
- yderligere læsning
Introduktion til kort, Reducer og filtrer
når du bygger iOS apps, du bruger typisk proceduremæssig eller objektorienteret programmering. Funktionel programmering er anderledes: den beskæftiger sig kun med funktioner. Ingen variabler, ingen tilstand, Ingen for-loops-bare funktioner.
det hurtige programmeringssprog egner sig perfekt til at blande funktionel programmering med ikke-funktionelle tilgange, som OOP. Du behøver ikke strengt skrive funktionel kode, og vedtagelse af koncepter fra funktionel programmering kan hjælpe dig med at lære at kode bedre.
funktionerne map(_:)
, reduce(_:_:)
og filter(_:)
kaldes højere ordensfunktioner, fordi de tager en funktion som input-og returfunktioner som output. Teknisk returnerer hurtig resultaterne af en operation (dvs. et transformeret array) ved brug af højere ordensfunktioner, mens et rent funktionelt sprog returnerer en samling funktioner. I hurtig er indgangene til disse funktioner lukninger.
Sådan fungerer de:
- funktionen
map()
anvender en funktion på hvert element i en samling. Tænk på at” kortlægge ” eller omdanne et sæt værdier til et andet sæt værdier. - funktionen
reduce()
forvandler en samling til en værdi. Tænk på det som at kombinere mange værdier i en, som gennemsnittet af et sæt tal. - funktionen
filter()
returnerer simpelthen værdier, der bestod enif
-sætning, og kun hvis denne betingelse resulterede itrue
.
hvis du tænker: “Se, jeg har ikke brug for funktionel programmering eller databehandling, fordi mine apps ikke gør det!”så stop ikke her. I de seneste appprojekter har jeg brugt kort, reducere og filtrere ved flere lejligheder:
- filtrering af omkostnings – /indtægtsværdier med
filter(_:)
, for at opfylde en tærskel, inden værdierne vises i en linjegraf - gennemsnit af tusinder af filmvurderinger til en værdi med
reduce(_:_:)
- kortlægning af et par operationer på en streng med hashtags, omdannelse til en normaliseret samling med
map(_:)
du kunne have løst alle disse problemer med en for-loop, men du vil se, at brug af map()
, reduce()
og filter()
resulterer i mere kortfattet, læsbar og performant kode.
Hurtig Start: Funktioner i højere orden i hurtig
vi vil fokusere på map()
, reduce()
og filter()
i denne tutorial. Før vi går videre, her er et hurtigt overblik over de mest almindelige funktioner med højere orden i hurtig:
-
map(_:)
sløjfer over hvert element i en sekvens, anvender en funktion på hvert element og returnerer det transformerede resultat -
reduce(_:_:)
sløjfer over hvert element i en sekvens, kombinerer dem til en værdi og returnerer det kombinerede resultat -
filter(_:)
sløjfer over hvert element i en sekvens og returnerer en resulterende sekvens, der kun indeholder elementer, der opfylder en given filtreringsfunktion -
flatMap(_:)
gør det samme sommap(_:)
, bortset fra at det flader den resulterende sekvens, dvs. indlejrede arrays er ikke-indlejrede eller “udfladede” -
compactMap(_:)
gør det samme sommap(_:)
, bortset fra at det fjernernil
værdier fra den resulterende sekvens, før den returneres
du kan bruge disse funktioner på arrays, ordbøger, sæt, intervaller, sekvenser og enhver anden hurtig type, du kan gentage over. Hvis du vil lære mere om compactMap(_:)
og flatMap(_:)
, så tjek denne tutorial.
flere typer i hurtig, såsom Array og Ordbog, har funktioner, der accepterer lukninger som input. Et hurtigt valg:
-
contains(where:)
sløjfer over en samling, anvender et prædikat (en lukning) på hvert element, returnerer entrue
, hvis et element opfylder prædikatet, ellersfalse
-
first(where:)
sløjfer over en samling, anvender et prædikat (en lukning) på hvert element og returnerer elementet, hvis det opfylder prædikatet -
firstIndex(where:)
gør det samme somfirst(where:)
, bortset fra at det returnerer indekset i stedet for værdien
du kan lære mere om disse funktioner i denne vejledning. Hvordan where
bruges i hurtig er også interessant, du kan lære mere om det i denne vejledning.
du har set “kort” og “reducere” funktioner i hurtig skrevet som map(_:)
og reduce(_:_:)
i hele denne tutorial. Understregningerne og kolonerne i disse funktioner er en del af funktionens signatur, som er et specielt format til at indikere funktionsparametre. For eksempel har funktionen map(_:)
en navngivet parameter, mens funktionen reduce(_:_:)
har to. Du kan lære mere om det i denne vejledning: funktioner i hurtig forklaret.

bliv ansat som iOS-udvikler
Lær at bygge iOS 14-apps med hurtig 5
Tilmeld dig mit iOS-udviklingskursus, og lær, hvordan du starter din karriere som professionel iOS-udvikler.
brug af funktionen kort
funktionen map(_:)
sløjfer over hvert element i en samling og anvender en handling på hvert element i samlingen. Det returnerer en samling af resulterende elementer, som operationen blev anvendt på.
lad os se på et eksempel. Vi har en række temperaturer i Celsius, som du vil omdanne til Fahrenheit.
du kan bruge en for-loop, som denne:
let celsius = var fahrenheit: = for value in celsius { fahrenheit += }print(fahrenheit)// Output:
koden fungerer fint, men det er for verbose. Du har brug for en foranderlig “hjælper” – variabel fahrenheit
for at gemme de beregnede konverteringer, mens du arbejder igennem dem, og du har brug for 3 linjer kode til selve konverteringen.
sådan kan vi gøre det samme med funktionen map(_:)
:
lad fahrenheit = celsius.kort { $0 * (9/5) + 32 }
print (fahrenheit)
du kan endda gøre alt det på en linje:
.map { * (9/5) + 32 }
Hvad sker der her?
- en konstant
celsius
er defineret, en række fordoblinger og initialiseret med et par tilfældige Celsius-værdier. - funktionen
map(_:)
kaldes påcelsius
arrayet. Funktionen har et argument, en lukning, der konverterer fra Celsius til Fahrenheit. - endelig udskrives resultatet: det konverterede array, fra Celsius til Fahrenheit.
funktionen map(_:)
omdanner et array til et andet ved at anvende en funktion på hvert element i arrayet. Lukningen * (9/5) + 32
tager inputværdien i Celsius og returnerer en værdi i Fahrenheit. Det resulterende array af map(_:)
er opbygget ud af disse konverterede værdier.
lad os se nærmere på lukningen. Hvis du har arbejdet med lukninger før, genkender du syntaksen for kort lukning. Det er en kortere måde at kode en lukning ved at udelade meget af dens syntaks.
her er et mindre kortfattet alternativ:
let celsius = let fahrenheit = celsius.map({ (value: Double) -> Double in return value * (9/5) + 32})print(fahrenheit)
den faktiske map(_:)
funktion opkald, og dens lukning, er dette:
··· = celsius.map({ (value: Double) -> Double in return value * (9/5) + 32})
Hvad sker der der? Funktionen map(_:)
kaldes på arrayet celsius
. Det kræver et argument: en lukning af typen (Double) -> Double
.
den første del af lukningen, der starter med {
, angiver, at denne Lukning har en parameter value
af typen Double
, og lukningen returnerer en værdi af typen Double
. Lukkekroppen, der starter med return
, returnerer simpelthen resultatet af Celsius til Fahrenheit-beregningen.
hvis du sammenligner syntaksen for kort lukning med den udvidede kode ovenfor, vil du se det:
- funktionsparenteserne
(
og)
udelades, fordi du kan udelade dem, når den sidste parameter i et funktionsopkald er en lukning. -
() -> in
delen kan udelades, fordi hurtig kan udlede, at du bruger enDouble
parameter som input og forventes at returnere enDouble
. Nu hvor du har udeladtvalue
variablen, kan du bruge den korte hånd.
- udsagnet
return
kan også udelades, fordi denne lukning forventes at returnere resultatet af et udtryk alligevel.
selvom ovenstående kodeeksempel bruger Double
typer, er du ikke begrænset til disse typer. Den resulterende type af en map()
funktion kan have en anden type end hvad du lægger i den, og du kan også bruge map()
på en Dictionary
.
lad os gå videre til reduce(_:_:)
!
brug af funktionen reducer
funktionen reduce(_:_:)
sløjfer over hvert element i en samling og reducerer dem til en værdi. Tænk på det som at kombinere flere værdier i en.
reduceringsfunktionen er måske den sværeste af kort, Reducer, filtrer at forstå. Hvordan kan du gå fra en samling af værdier til en værdi?
et par eksempler:
- oprettelse af en sum af flere værdier, dvs.
3 + 4 + 5 = 12
- sammenkædning af en samling af strenge, dvs.
= "Zaphod, Trillian, Ford"
- gennemsnit af et sæt værdier, dvs.
(7 + 3 + 10) / 3 = 7/3 + 3/3 + 10/3 = 6.667
i databehandling kan du forestille dig mange scenarier, når enkle operationer som disse er nyttige. Som før kan du løse et af disse problemer med en for-loop, men reduce(_:_:)
er simpelthen kortere og hurtigere.
her er hvordan:
lad sum = værdier.reducer (0,+)
print (sum)
funktionen reduce(_:_:)
tager to argumenter, en startværdi og en lukning. I ovenstående kode leverer vi +
operatøren, det er også en funktion med to parametre.
du kan selvfølgelig også give din egen lukning:
lad gennemsnit = værdier.reducer (0.0) { $0 + $1 } / dobbelt (værdier.antal)
Udskriv (gennemsnit)
i eksemplet ovenfor beregner du gennemsnittet af tre tal. Typerne af værdierne i koden er alle Double
. Vi tilføjer først alle numrene og deler det derefter med antallet af tal.
reduce(_:_:)
funktionen er forskellig på to måder:
- funktionen
reduce(_:_:)
har to unavngivne parametre; den oprindelige værdi og lukningen - lukningen, der leveres til
reduce(_:_:)
, har også to parametre; det aktuelle resultat af reduktionen og den nye værdi, der er ved at blive reduceret
her, tjek dette ud:
lad sum = værdier.reducer (0) {
Udskriv(“\($0) + \($1) = \($0 + $1)”)
tilbage $0 + $1
}
Udskriv (sum)
i ovenstående eksempel kan du tydeligt se og
, de 2 parametre for lukningerne. Når du kører koden, er dette det output, du får:
0 + 7 = 77 + 3 = 1010 + 10 = 2020
se hvordan vi starter med 0
og derefter tilføjer 7
? I det næste trin tager vi 7
– den aktuelle reduktionsværdi-og tilføjer 3
, den “næste” værdi i reduktionen.
her er en anden måde at se på det:
0 + 7(0 + 7) + 3((0 + 7) + 3) + 10
dette gør det også klart, hvorfor du har brug for en startværdi for reduce(_:_:)
, fordi det er den første første parameter for lukningen.
reduktion kan være vanskelig at forstå. Det er vigtigt at forstå, at du iterativt anvender en handling, som +
, på et sæt værdier, indtil du kun har en værdi. Du reducerer bogstaveligt talt mængden af værdier.
lad os gå videre til filter(_:)
!
brug af Filterfunktionen
funktionen filter
sløjfer over hvert element i en samling og returnerer en samling, der kun indeholder elementer, der opfylder en inklusionsbetingelse.
det er som at anvende en if
-sætning til en samling og kun holde de værdier, der passerer betingelsen.
her, tjek dette ud:
lad lige = værdier.filter { $0.isMultiple (af: 2)}
print (selv)
i ovenstående eksempel filtrerer du tal fra values
, der er lige. Funktionen isMultiple(of:)
returnerer true
når kan divideres med
2
og false
ellers.
i modsætning til map(_:)
og reduce(_:_:)
skal lukningen filter(_:)
returnere en boolsk, så enten true
eller false
. Når lukningen returnerer true
, holdes værdien, og når false
returneres, udelades værdien. Det er sådan filter(_:)
filtrerer input array.
her er et lidt klarere eksempel, med lukningen udvidet:
let values = let even = values.filter({ (value:Int) -> Bool in return value.isMultiple(of: 2)})print(even) // Output:
i eksemplet returnerer lukningen en boolsk værdi, angivet med -> Bool
. Det leveres en parameter, elementet i samlingen, og returnerer resultatet af isMultiple(of:)
. Pænt!
kombination af kort, Reducer og filtrer
kan du kombinere funktionerne map()
, reduce()
og filter()
? Sikker på at du kan!
lad os sige, at vi har en klasse af studerende. Du kender året hver elev blev født. Du vil beregne den samlede alder for alle studerende født i eller efter 2000.
Sådan gør du det:
lad år =
lad sum = år.filter({ $0 >= 2000 }).kort ({nu – $0 }).reducer (0,+)
print (sum)
ovenstående kodeprøve bruger kæde. Det bruger resultatet af en funktion som input til en anden, der kombinerer kort-Reducer-filter. Funktionen map()
kaldes på resultatarrayet for funktionen filter()
, og funktionen reduce()
kaldes på resultatet af funktionen map()
. Fedt!
selve koden er enkel:
- lav en konstant
now
ogyears
, og tildele en masse år til det. - Filtrer de år, der er under 2000, dvs. behold dem, for hvilke
>= 2000
ertrue
- Transformer hvert år til en alder ved at trække året fra
now
- Tilføj alle aldre op ved at reducere med
+
lad os tage et mere interessant eksempel. Tjek følgende kode, taget fra tutorial om Boblebad:
skift (i % 3 = = 0, i % 5 == 0)
{
case (true, false):
return”boblevand”
sag (false, true):
return”brummer”
sag (true, true):
return”boblevand”
standard:
tilbage “\(jeg)”
}
}
lad resultat = Array (2…100).kort(boblebad).reducer(“1”, { $0 + “, ” + $1 })
Udskriv (resultat)
se hvad sker der? Vi omdanner et array med tal fra 2 til 100 til enten “brummer”, “brummer” eller “brummer” med map(_:)
, baseret på spillets regler. Endelig reducerer vi denne række strenge til en stor streng med reduce(_:_:)
, der kombinerer hver værdi. Pænt!
yderligere læsning
hvad hvis du skulle kode alt dette med for in
loops? Du ville bruge meget mere kode. Og det er kort-reducere-filter magt: det er mere kortfattet, ofte lettere at læse, og — indrøm det — pretty damn cool!
vil du vide mere? Tjek disse ressourcer:
- Sådan bruges “hvor” i hurtig
- FlatMap og CompactMap forklaret i hurtig
- den ultimative Guide til lukninger i hurtig
- Sådan: Find et emne i et Array i hurtig
- spil med kode: Binær søgning i hurtig
- kom i gang med legepladser

bliv ansat som iOS-udvikler
Lær at bygge iOS 14-apps med hurtig 5
Tilmeld dig mit iOS-udviklingskursus, og lær, hvordan du starter din karriere som professionel iOS-udvikler.