kirjoittanut Reinder de Vries on July 9 2020 In App Development, Swift

karttaa, vähennä ja suodata Swiftissä

Swiftissä käytät map(), reduce() ja filter() kokoelmien, kuten taulukoiden ja sanakirjojen, silmukoimiseen ilman for-Loopia.

kartta -, pelkistys-ja suodatusfunktiot tulevat funktionaalisen ohjelmoinnin (FP) valtakunnasta. Niitä kutsutaan korkeamman kertaluvun funktioiksi, koska ne ottavat funktioita syötteenä. Sovellat funktiota matriisiin, esimerkiksi, muuttaaksesi sen dataa.

Swiftin kartta -, vähennä-ja suodatustoiminnot voivat olla haastavia kääriä pään ympärille. Varsinkin, jos on aina koodannut for in silmukoita iterointiongelmien ratkaisemiseksi. Tässä oppaassa opit käyttämään map(_:), reduce(_:_:) ja filter(_:) funktioita Swiftissä.

Let ’ s get started!

  1. Johdatus karttaan, vähennä ja suodata
  2. Pikakäynnistys: Higher-Order Functions in Swift
  3. Using the Map Function
  4. Using the Reduce Function
  5. Using the Filter Function
  6. Combining Map, Reduce and Filter
  7. Further Reading

Introduction to Map, Reduce and Filter

When you ’ re building iOS Sovellukset, käytät tyypillisesti prosessuaalista tai olio-ohjelmointia. Funktionaalinen ohjelmointi on erilaista: se käsittelee vain funktioita. Ei muuttujia, ei tilaa, ei for-silmukoita-vain toimintoja.

Swift-ohjelmointikieli soveltuu erinomaisesti funktionaalisen ohjelmoinnin sekoittamiseen ei-funktionaalisiin lähestymistapoihin, kuten OOP. Sinun ei tarvitse tiukasti kirjoittaa funktionaalista koodia, ja konseptien omaksuminen funktionaalisesta ohjelmoinnista voi auttaa sinua oppimaan koodaamaan paremmin.

map(_:), reduce(_:_:) ja filter(_:) funktioita kutsutaan korkeamman kertaluvun funktioiksi, koska ne ottavat funktion Tulo-ja paluufunktioina ulostulona. Teknisesti Swift palauttaa operaation tulokset (ts. transformed array) käytettäessä korkeamman kertaluvun funktioita, kun taas puhdas funktionaalinen kieli palauttaa joukon funktioita. Swiftissä näiden toimintojen syötteet ovat sulkemisia.

näin ne toimivat:

  • map() funktio soveltaa funktiota jokaiseen kokoelman esineeseen. Ajatelkaa ”kartoittamista” tai yhden arvojoukon muuttamista toiseksi arvojoukoksi.
  • reduce() funktio muuttaa kokoelman yhdeksi arvoksi. Ajattele, että se yhdistää monia arvoja yhdeksi, kuin keskiarvona joukko lukuja.
  • filter() funktio yksinkertaisesti palauttaa arvot, jotka läpäisivät if-lausekkeen, ja vain jos tämä ehto johti true.

jos ajattelet: ”katso, en tarvitse funktionaalista ohjelmointia tai tietojenkäsittelyä, koska sovellukseni eivät sitä tee!”älä sitten pysähdy tähän. Viimeaikaisissa sovellusprojekteissa olen käyttänyt karttaa, vähennä ja suodata useaan otteeseen:

  • Filtering cost / revenue values with filter(_:), to meet a border, before showing the values in a line graph
  • Average thousands of movie ratings into one value with reduce(_:_:)
  • Mapping a few operations on a string with hashtags, transforming it into a normal collection, with map(_:)

voit ratkaista kaikki nämä ongelmat for-loop, mutta huomaat, että käyttämällä map(), reduce() ja filter() johtaa suppeampi, luettava ja toimiva koodi.

Pikakäynnistys: Korkeamman kertaluvun funktiot Swiftissä

keskitymme tässä opetusohjelmassa map(), reduce() ja filter(). Ennen kuin siirrymme eteenpäin, tässä on nopea katsaus Swiftin yleisimpiin korkeamman kertaluvun toimintoihin:

  • map(_:) silmukat jokaisen kohteen päälle jonossa, soveltaa funktiota jokaiseen alkuaineeseen ja Palauttaa muunnetun tuloksen
  • reduce(_:_:) silmukat jokaisen kohteen päälle jonossa, yhdistää ne yhdeksi arvoksi ja palauttaa yhdistetyn tuloksen
  • filter(_:) silmukat jokaisen kohteen päälle jonossa ja palauttaa tuloksena olevan sekvenssin, joka sisältää vain kohteita, jotka täyttävät tietyn suodatusfunktion
  • flatMap(_:) tekee saman kuin map(_:), paitsi että se litistää tuloksena sekvenssi, so. sisäkkäiset ryhmät ovat sisäkkäisiä tai ”litistettyjä””
  • compactMap(_:) tekee saman kuin map(_:), paitsi että se poistaa nil arvot syntyneestä sekvenssistä ennen sen palauttamista

voit käyttää näitä funktioita taulukoissa, sanakirjoissa, sarjoissa, vaihteluväleissä, sekvensseissä ja missä tahansa muussa Swift-tyypissä, jonka voit toistaa. Jos haluat lisätietoja compactMap(_:): stä ja flatMap(_:): stä, tutustu tähän opetusohjelmaan.

useilla Swiftin tyypeillä, kuten Array ja Dictionary, on funktiot, jotka hyväksyvät sulkeumat syötteenä. Nopea valinta:

  • contains(where:) loops over a collection, applices a predikate (a closure) to every item, returns a true if a item supposes the predikate, otherwise false
  • first(where:) silmukoita kokoelman päälle, soveltaa predikaatin (sulkimen) jokaiseen alkioon ja palauttaa kohteen, jos se täyttää predikaatin
  • firstIndex(where:) tekee saman kuin first(where:), paitsi että se palauttaa indeksin arvon

sijaan, voit lukea lisää näistä funktioista tässä tutoriaalissa. Se, miten where käytetään Swiftissä, on myös mielenkiintoista, voit oppia siitä lisää tässä opetusohjelmassa.

olet nähnyt Swiftin ”map” – ja ”reduce” – funktiot kirjoitettuna map(_:) ja reduce(_:_:) koko tämän opetusohjelman ajan. Näiden funktioiden alaviivat ja kärjet ovat osa funktion signaalia, joka on erityinen formaatti funktioparametrien ilmaisemiseksi. Esimerkiksi map(_:) funktiolla on yksi nimeämätön parametri, kun taas reduce(_:_:) funktiolla on kaksi. Voit oppia lisää tästä opetusohjelma: toiminnot Swift selitti.

Hanki työpaikka iOS-kehittäjänä

Opi rakentamaan iOS 14-sovelluksia Swift 5: llä

Rekisteröidy iOS development course-kurssille ja opi aloittamaan urasi ammattimaisena iOS-kehittäjänä.

käyttämällä Karttafunktiota

map(_:) funktio silmukoi jokaisen kokoelman kohteen ja soveltaa operaation jokaiselle kokoelman alkuaineelle. Se palauttaa kokoelman tuloksena olevia kohteita, joihin toimenpidettä sovellettiin.

katsotaanpa esimerkkiä. Meillä on joukko celsiusasteita, jotka haluat muuttaa Fahrenheitiksi.

voit käyttää for-Loopia, kuten tämä:

let celsius = var fahrenheit: = for value in celsius { fahrenheit += }print(fahrenheit)// Output: 

koodi toimii hyvin, mutta se on liian monisanainen. Tarvitset muunneltavan ”auttaja” – muuttujan fahrenheit tallentamaan lasketut muunnokset työstäessäsi niitä, ja tarvitset 3 riviä koodia itse muunnosta varten.

näin voimme tehdä saman map(_:) funktiolla:

let celsius =
let fahrenheit = celsius.kartta { $0 * (9/5) + 32 }
printti(fahrenheit)
piilota varoitukset

voit jopa tehdä kaiken tuon yhdellä rivillä:

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

mitä täällä tapahtuu?

  1. määritellään vakio celsius, joukko tuplaa, ja alustetaan muutamalla satunnaisella Celsiusarvolla.
  2. funktio map(_:) on nimeltään celsius array. Funktiolla on yksi argumentti, sulkeuma, joka muuntuu Celsiuksesta Fahrenheitiksi.
  3. lopuksi tulostetaan tulos: muunnettu array, Celsiuksesta fahrenheitiin.

map(_:) funktio muuttaa yhden joukon toiseksi soveltamalla funktiota jokaiseen joukon alkioon. Sulkeuma * (9/5) + 32 ottaa tuloarvon Celsius – arvona ja palauttaa arvon Fahrenheit-arvona. Saatu joukko map(_:) rakentuu näistä muunnetuista arvoista.

katsotaan tarkemmin sulkemista. Jos olet työskennellyt sulkujen kanssa aiemmin, tunnistat lyhyen käden sulkemissyntaksin. Se on lyhyempi tapa koodata sulkeminen, jättämällä pois suuri osa sen syntaksista.

tässä suppeampi vaihtoehto:

let celsius = let fahrenheit = celsius.map({ (value: Double) -> Double in return value * (9/5) + 32})print(fahrenheit)

varsinainen map(_:) funktiokutsu ja sen päättyminen on tämä:

··· = celsius.map({ (value: Double) -> Double in return value * (9/5) + 32})

mitä siellä tapahtuu? map(_:) funktiota kutsutaan array celsius. Tarvitaan yksi argumentti: tyypin (Double) -> Double sulkeminen.

sulkemisen ensimmäinen osa, joka alkaa numerolla {, osoittaa, että sulkemisella on yksi parametri value tyyppiä Double, ja sulkeminen palauttaa arvon tyyppi Double. Sulkuelin, joka alkaa numerolla return, yksinkertaisesti palauttaa Celsiuksen tuloksen Fahrenheit-laskelmaan.

jos vertaat lyhyen käden sulkemissyntaksia yllä olevaan laajennettuun koodiin, näet, että:

  • funktiosulkeet ( ja ) jätetään pois, koska ne voi jättää pois, kun funktiokutsun viimeinen parametri on sulkeminen.
  • () -> in – osa voidaan jättää pois, koska Swift voi päätellä, että käytät yhtä Double – parametria syötteenä, ja sen odotetaan palauttavan Double. Nyt kun olet jättänyt pois value muuttujan, voit käyttää lyhyttä kättä .
  • return lauseke voidaan jättää myös pois, koska tämän sulkemisen odotetaan palauttavan lausekkeen tuloksen joka tapauksessa.

vaikka yllä oleva koodinäyte käyttää Double tyyppejä, ei ole rajattu näihin tyyppeihin. Syntyvällä funktion a map() tyypillä voi olla eri tyyppi kuin mitä siihen laitetaan, ja map() voidaan käyttää myös a Dictionary.

siirrytään reduce(_:_:)!

käyttäen Pelkistysfunktiota

reduce(_:_:) funktiosilmukat jokaisen kokoelman kohteen yli ja pelkistää ne yhteen arvoon. Ajattele, että se yhdistää useita arvoja yhdeksi.

reduction-funktio on ehkä vaikeinta kartasta, reductionista, suodattimesta ymmärtää. Miten arvokokoelmasta voi siirtyä yhteen arvoon?

muutamia esimerkkejä:

  • luodaan useiden arvojen summa, eli 3 + 4 + 5 = 12
  • kasataan merkkijonokokoelma, eli = "Zaphod, Trillian, Ford"
  • lasketaan keskiarvoksi joukko arvoja, ts.(7 + 3 + 10) / 3 = 7/3 + 3/3 + 10/3 = 6.667

tietojenkäsittelyssä, voit kuvitella paljon skenaarioita, kun yksinkertaisia toimintoja, kuten nämä ovat käteviä. Kuten ennenkin, voit ratkaista minkä tahansa näistä ongelmista for-Loopilla, mutta reduce(_:_:) on yksinkertaisesti lyhyempi ja nopeampi.

näin:

let-arvot =
let sum = arvot.vähennä (0,+)
tulosta (summa)
piilota varoitukset

funktio reduce(_:_:) vaatii kaksi parametria, alkuarvon ja sulkemisen. Yllä olevassa koodissa annetaan + operaattori, sekin on funktio, jossa on kaksi parametria.

voit tietysti myös itse päättää:

let-arvot =
let average = arvot.vähennä (0.0) { $0 + $1 } / kaksinkertainen (arvot.lukumäärä)
tulosta (keskiarvo)
piilota varoitukset

yllä olevassa esimerkissä lasketaan kolmen luvun keskiarvo. Koodin arvojen tyypit ovat kaikki Double. Laskemme ensin yhteen kaikki numerot ja jaamme sen sitten numeroiden määrällä.

reduce(_:_:) funktio eroaa kahdella tavalla:

  1. funktiolla reduce(_:_:) on kaksi nimeämätöntä parametria; alkuarvolla ja sulkemisella
  2. reduce(_:_:) annetulla sulkemisella on myös kaksi parametria; nykyinen vähennystulos, ja uusi arvo, joka on vähenemässä

tästä, tsekkaa tämä:

let-arvot =
let sum = arvot.vähennä (0) {
tulosta(”\($0) + \($1) = \($0 + $1)”)
paluu $0 + $1
}
printti (summa)
piilota varoitukset

yllä olevassa esimerkissä näet selvästi ja sulkujen 2 parametria. Kun käytät koodia, tämä on lähtö saat:

0 + 7 = 77 + 3 = 1010 + 10 = 2020

Näetkö, miten aloitamme 0: stä ja lisäämme sitten 7? Seuraavassa vaiheessa otetaan 7 – nykyinen vähennysarvo-ja lisätään 3, vähennyksen ”seuraava” arvo.

Tässä toinen tapa tarkastella sitä:

0 + 7(0 + 7) + 3((0 + 7) + 3) + 10

tämä tekee myös selväksi, miksi reduce(_:_:): lle tarvitaan alkuarvo, koska se on sulkemisen ensimmäinen ensimmäinen parametri.

pelkistystä voi olla hankala käsittää. On tärkeää ymmärtää, että operaatiota, kuten +, sovelletaan iteratiivisesti johonkin arvojoukkoon, kunnes jäljelle jää vain yksi arvo. Sinä kirjaimellisesti vähennät arvojen määrää.

siirrytään filter(_:)!

käyttäen Suodatusfunktiota

filter funktio loopsahtaa jokaisen kokoelman kohteen päälle ja palauttaa kokoelman, joka sisältää vain sellaisia kohteita, jotka täyttävät include-ehdon.

se on kuin soveltaisi if-lausetta kokoelmaan, ja pitäisi vain ne arvot, jotka läpäisevät ehdon.

tsekkaa tästä:

let-arvot =
let even = arvot.suodatin { $0.isMultiple (of: 2) }
print (even)
piilota varoitukset

yllä olevassa esimerkissä suodatat numeroita values, jotka ovat parillisia. isMultiple(of:) funktio palauttaa true, kun voidaan jakaa 2, ja false muuten.

toisin kuin map(_:) ja reduce(_:_:), sulkijan filter(_:) on palautettava Boolen, joten joko true tai false. Päätteen palautuessa true arvo pidetään, ja kun false palautetaan, arvo jätetään pois. Näin filter(_:) suodattaa tulorivin.

tässä hieman selkeämpi esimerkki, jossa sulkemista laajennettiin:

let values = let even = values.filter({ (value:Int) -> Bool in return value.isMultiple(of: 2)})print(even) // Output: 

esimerkissä sulkeminen palauttaa Boolen arvon, joka merkitään merkinnällä -> Bool. Se tarjoaa yhden parametrin, kokoelman kohteen, ja palauttaa tuloksen isMultiple(of:). Siistiä!

yhdistämällä kartta, pelkistys ja suodatus

voitko yhdistää map(), reduce() ja filter() funktiot? Totta kai voit!

sanotaan, että meillä on oppilasluokka. Tiedät jokaisen oppilaan syntymävuoden. Haluat laskea kaikkien vuonna 2000 tai sen jälkeen syntyneiden opiskelijoiden yhteenlasketun iän.

Näin teet sen:

let now = 2020
let years =
let sum = years.suodatin({ $0 >= 2000 }).kartta ({nyt – $0}).vähennä (0,+)
tulosta (summa)
piilota varoitukset

yllä olevassa koodinäytteessä käytetään ketjutusta. Se käyttää yhden funktion tulosta syötteenä toiselle, yhdistämällä kartta-vähennä-suodatin. map() funktiota kutsutaan filter() funktion tulosjoukolle ja reduce() funktiota kutsutaan map() funktion tulokselle. Mahtavaa!

itse koodi on yksinkertainen:

  1. tehdään vakio now ja years, ja annetaan sille joukko vuosia.
  2. suodattaa pois vuoden 2000 alle jäävät vuodet, ts. pitäkää ne, joiden osalta >= 2000 on true
  3. muunnetaan joka vuosi ikään vähentämällä vuodesta now
  4. kaikki ikäluokat ylös, vähentämällä +

otetaan mielenkiintoisempi esimerkki. Tutustu seuraava koodi, otettu opetusohjelma noin FizzBuzz:

let fizzbuzz: (Int) -> String = { i in
switch (I % 3 = = 0, i % 5 == 0)
{
case (true, false):
return ”Fizz”
case (false, true):
return ”Buzz”
case (true, true):
return ”FizzBuzz”
default:
paluu ” \(i)”
}
}
olkoon tulos = Array (2…100).kartta (fizzbuzz).pienennä(”1”, { $0 + ”, ” + $1 })
printti(tulos)
piilota varoitukset

Katso mitä tapahtuu? Muunnamme joukon numeroilla 2-100 joko ”Fizziksi”, ”Buzziksi” tai ”Fizzbuzziksi” map(_:) pelin sääntöjen mukaan. Lopuksi pelkistämme tuon merkkijonojen joukon yhdeksi suureksi merkkijonoksi, jossa on reduce(_:_:), yhdistäen jokaisen arvon. Siistiä!

Jatkoluku

mitä jos joutuisit koodaamaan kaiken tämän for in silmukoilla? Käyttäisit enemmän koodia. Ja se on map-reduce-Filterin teho: se on ytimekkäämpi, usein helppolukuisempi, ja — myönnä se — aika hiton siistiä!

Haluatko oppia lisää? Tutustu näihin resursseihin:

  • How to Use ”where” in Swift
  • FlatMap And CompactMap Explained In Swift
  • the Ultimate Guide to Closures in Swift
  • How To: Find an Item In An Array In Swift
  • Play With Code: Binäärihaku Swiftissä
  • Aloita Xcode Playgrounds

Hanki työpaikka iOS-kehittäjänä

Opi rakentamaan iOS 14-sovelluksia Swift 5: llä

Rekisteröidy iOS development course-kurssille ja opi aloittamaan urasi ammattimaisena iOS-kehittäjänä.

Vastaa

Sähköpostiosoitettasi ei julkaista.