skrevet af Reinder de Vries den 9. juli 2020 i appudvikling, hurtig

Kortlæg, reducer og filtrer i 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!

  1. Introduktion til kort, Reducer og filtrer
  2. Hurtig Start: Funktioner i højere orden i hurtig
  3. brug af kortfunktionen
  4. brug af Reducer-funktionen
  5. brug af Filterfunktionen
  6. kombination af kort, Reducer og filtrer
  7. 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 en if-sætning, og kun hvis denne betingelse resulterede i true.

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 medfilter(_:), 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 som map(_:), bortset fra at det flader den resulterende sekvens, dvs. indlejrede arrays er ikke-indlejrede eller “udfladede”
  • compactMap(_:) gør det samme som map(_:), bortset fra at det fjerner nil 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 en true, hvis et element opfylder prædikatet, ellers false
  • 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 som first(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 celsius =
lad fahrenheit = celsius.kort { $0 * (9/5) + 32 }
print (fahrenheit)
Skjul advarsler

du kan endda gøre alt det på en linje:

.map {  * (9/5) + 32 }

Hvad sker der her?

  1. en konstant celsius er defineret, en række fordoblinger og initialiseret med et par tilfældige Celsius-værdier.
  2. funktionen map(_:) kaldes på celsius arrayet. Funktionen har et argument, en lukning, der konverterer fra Celsius til Fahrenheit.
  3. 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 valueaf 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 en Double parameter som input og forventes at returnere en Double. Nu hvor du har udeladt value 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 værdier =
lad sum = værdier.reducer (0,+)
print (sum)
Skjul advarsler

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 værdier =
lad gennemsnit = værdier.reducer (0.0) { $0 + $1 } / dobbelt (værdier.antal)
Udskriv (gennemsnit)
Skjul advarsler

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:

  1. funktionen reduce(_:_:) har to unavngivne parametre; den oprindelige værdi og lukningen
  2. 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 værdier =
lad sum = værdier.reducer (0) {
Udskriv(“\($0) + \($1) = \($0 + $1)”)
tilbage $0 + $1
}
Udskriv (sum)
Skjul advarsler

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 0og 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 værdier =
lad lige = værdier.filter { $0.isMultiple (af: 2)}
print (selv)
Skjul advarsler

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 trueeller 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 nu = 2020
lad år =
lad sum = år.filter({ $0 >= 2000 }).kort ({nu – $0 }).reducer (0,+)
print (sum)
Skjul advarsler

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:

  1. lav en konstant now og years, og tildele en masse år til det.
  2. Filtrer de år, der er under 2000, dvs. behold dem, for hvilke >= 2000 er true
  3. Transformer hvert år til en alder ved at trække året fra now
  4. 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:

(Int) – > String = { i i
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)
Skjul advarsler

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.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.