írta: Reinder de Vries, július 9, 2020 in App Development, Swift

leképezés, kicsinyítés és szűrés Swift

Swiftben a map(), reduce() és filter() használatával hurkolhatja a gyűjteményeket, például tömböket és szótárakat, for-hurok használata nélkül.

a map, reduce és filter függvények a funkcionális programozás (FP) területéről származnak. Magasabb rendű függvényeknek hívják őket, mert bemenetnek veszik a függvényeket. Függvényt alkalmaz egy tömbre, például az adatok átalakítására.

a Swift Térkép -, Reduce-és Szűrőfunkciói kihívást jelenthetnek a fej körül. Különösen akkor, ha mindig for in hurkokat kódolt az iterációs problémák megoldására. Ebben az útmutatóban megtudhatja, hogyan kell használni a map(_:), reduce(_:_:) és filter(_:) funkciókat Swift-ben.

kezdjük!

  1. Bevezetés a térképbe, Csökkentésbe és szűrésbe
  2. gyors indítás: Magasabb rendű funkciók a Swift-ben
  3. a térkép funkció használata
  4. a Csökkentés funkció használata
  5. a szűrő funkció használata
  6. a térkép, a csökkentés és a szűrő kombinálása
  7. további olvasmányok

Bevezetés a térképbe, a Csökkentésbe és a szűrésbe

amikor iOS-t épít alkalmazások, általában eljárási vagy objektum-orientált programozást használ. A funkcionális programozás más: csak a funkciókkal foglalkozik. Nincs változó, nincs állapot, nincs for-hurok — csak függvények.

a Swift programozási nyelv tökéletesen alkalmas a funkcionális programozás nem funkcionális megközelítésekkel való keverésére, mint például az OOP. Nem kell szigorúan funkcionális kódot írni, és a funkcionális programozásból származó fogalmak elfogadása segíthet megtanulni, hogyan kell jobban kódolni.

a map(_:), reduce(_:_:) és filter(_:) függvényeket magasabb rendű függvényeknek nevezzük, mert egy függvényt inputnak, a return függvényt kimenetként vesznek fel. Technikailag a Swift egy művelet eredményeit adja vissza (pl. transzformált tömb), ha magasabb rendű függvényeket használ, míg a tiszta funkcionális nyelv függvénygyűjteményt ad vissza. A Swift-ben ezeknek a funkcióknak a bemenetei bezárások.

itt van, hogyan működnek:

  • a map() függvény egy függvényt alkalmaz a gyűjtemény minden elemére. Gondoljon a “leképezésre” vagy az egyik értékkészlet átalakítására egy másik értékkészletre.
  • a reduce() függvény egy gyűjteményt egyetlen értékké alakít. Gondolj arra, hogy sok értéket egyesít egybe, mint például egy számkészlet átlagolása.
  • a filter()függvény egyszerűen olyan értékeket ad vissza, amelyek if-utasításon mentek keresztül, és csak akkor, ha ez a feltétel true eredményt eredményezett.

abban az esetben, ha arra gondolsz: “nézd, nincs szükségem funkcionális programozásra vagy adatfeldolgozásra, mert az Alkalmazásaim nem ezt teszik!”akkor ne állj meg itt. A legutóbbi alkalmazásprojektekben több alkalommal használtam a térképet, a csökkentést és a szűrést:

  • szűrés költség / bevétel értékek filter(_:), hogy megfeleljen a küszöbértéket, mielőtt mutatja az értékeket egy vonal grafikon
  • átlagolása ezer film értékelés egy értéket reduce(_:_:)
  • leképezése néhány műveletet egy string hashtags, átalakítja azt egy normalizált gyűjtemény, a map(_:)

ezeket a problémákat megoldhattad volna egy For-hurokkal, de látni fogod, hogy a map(), reduce() és filter() használata tömörebb, olvashatóbb és hatékonyabb kódot eredményez.

Gyors Indítás: Magasabb rendű funkciók a Swift

ebben az oktatóanyagban a map(), reduce() és filter() témákra összpontosítunk. Mielőtt továbblépnénk, itt található egy gyors áttekintés A Swift leggyakoribb magasabb rendű funkcióiról:

  • map(_:) hurkok a sorozat minden elemére, függvényt alkalmaz minden elemre, és visszaadja a transzformált eredményt
  • reduce(_:_:) hurkok a sorozat minden elemére, egyesíti őket egy értékbe, és visszaadja a kombinált eredményt
  • filter(_:) hurkok a sorozat minden elemére, és visszaad egy kapott sorozatot, amely csak olyan elemeket tartalmaz, amelyek megfelelnek egy adott szűrési funkciónak
  • flatMap(_:) ugyanazt teszi, mint map(_:), kivéve, hogy ellapítja a kapott szekvenciát, azaz. beágyazott tömbök un-beágyazott vagy “lapított ki”
  • compactMap(_:) ugyanaz, mint a map(_:), azzal a különbséggel, hogy eltávolítja a nil értékeket az eredményül kapott szekvenciából, mielőtt visszaadná

ezeket a függvényeket tömbökön, szótárakon, készleteken, tartományokon, szekvenciákon és bármely más Swift-típuson használhatja. Ha többet szeretne megtudni a compactMap(_:) és flatMap(_:), akkor nézze meg ezt az oktatóanyagot.

a Swift számos típusa, például az Array és a Dictionary rendelkezik olyan funkciókkal, amelyek elfogadják a bezárásokat bemenetként. Gyors választás:

  • contains(where:) hurkok egy gyűjtemény felett, predikátumot (zárást) alkalmaz minden elemre, true értéket ad vissza, ha egy elem kielégíti a predikátumot, különben false
  • first(where:) hurkok egy gyűjtemény felett, predikátumot (zárást) alkalmaz minden elemre, és visszaadja az elemet, ha megfelel a predikátumnak
  • firstIndex(where:) ugyanaz, mint a first(where:), azzal a különbséggel, hogy az indexet adja vissza az érték helyett

ezekről a funkciókról többet megtudhat ebben az oktatóanyagban. A where használata a Swift-ben is érdekes, erről többet megtudhat ebben az oktatóanyagban.

a Swift-ben a “térkép” és a “csökkentés” függvényeket map(_:) és reduce(_:_:) néven írtad végig ebben az oktatóanyagban. Ezekben a függvényekben az aláhúzások és a kettőspontok a függvény aláírásának részét képezik, amely egy speciális formátum a függvényparaméterek jelzésére. Például a map(_:) függvénynek van egy meg nem nevezett paramétere, míg a reduce(_:_:) függvénynek kettő van. Erről többet megtudhat ebben az oktatóanyagban: funkciók a Swift-ben magyarázva.

jelentkezz iOS fejlesztőként

Tanuld meg, hogyan építhetsz iOS 14 alkalmazásokat a Swift 5 segítségével

regisztrálj a My iOS development course-ra, és tanuld meg, hogyan kezdheted el karriered professzionális iOS fejlesztőként.

a

Map függvény használata a map(_:) függvény a gyűjtemény minden elemére hurkol, és a gyűjtemény minden elemére egy műveletet alkalmaz. A kapott elemek gyűjteményét adja vissza, amelyre a műveletet alkalmazták.

nézzünk egy példát. Van egy sor hőmérsékletünk Celsius-ban, amit Fahrenheit-re akarsz átalakítani.

használhatsz egy for-loop-ot, mint ez:

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

a kód jól működik, de túl bőbeszédű. Szüksége van egy változtatható “helper” változóra fahrenheit a számított konverziók tárolásához, miközben dolgozik rajtuk, és magának a konverziónak 3 sornyi kódra van szüksége.

így tehetjük ugyanezt a map(_:) funkcióval:

legyen celsius =
legyen fahrenheit = celsius.térkép { $0 * (9/5) + 32 }
print (fahrenheit)
elrejtése figyelmeztetések

akkor is csinálni minden, hogy egy sorban:

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

mi történik itt?

  1. a konstans celsius definiálva van, páros tömbként, és néhány véletlenszerű Celsius értékkel inicializálva.
  2. a map(_:) függvényt a celsius tömbben hívják meg. A függvénynek van egy argumentuma, egy lezárása, amely Celsius-ról Fahrenheit-re konvertálódik.
  3. végül kinyomtatjuk az eredményt: az átalakított tömb, Celsius-tól Fahrenheit-ig.

a map(_:) függvény átalakítja az egyik tömböt egy másikba, egy függvény alkalmazásával a tömb minden elemére. A * (9/5) + 32 zárás a bemeneti értéket Celsius-ban veszi fel, és Fahrenheit értéket ad vissza. A kapott map(_:) tömb ezekből az átalakított értékekből épül fel.

vessünk egy közelebbi pillantást a lezárásra. Ha korábban már dolgozott bezárásokkal, felismeri a rövid kéz bezárásának szintaxisát. Ez egy rövidebb módszer a lezárás kódolására, a szintaxis nagy részének kihagyásával.

itt egy kevésbé tömör alternatíva:

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

a tényleges map(_:) függvényhívás és annak lezárása ez:

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

mi folyik ott? A map(_:) függvényt a celsius tömbben hívják meg. Egy érvre van szükség: (Double) -> Double típusú lezárás.

a lezárás első része, amely { – vel kezdődik, azt jelzi, hogy ennek a lezárásnak van egy value paramétere Doubletípusú, a lezárás pedig Double típusú értéket ad vissza. A zárótest return – vel kezdve egyszerűen visszaadja a Celsius eredményét Fahrenheit számításba.

ha összehasonlítja a rövid kéz zárási szintaxist a fenti kibővített kóddal, látni fogja, hogy:

  • a ( és ) zárójeleket kihagyjuk, mert ezeket kihagyhatjuk, ha a függvényhívás utolsó paramétere zárás.
  • az () -> in rész elhagyható, mert a Swift arra következtet, hogy egy Doubleparamétert használ bemenetként, és várhatóan Double értéket ad vissza. Most, hogy kihagyta a value változót, használhatja a rövid kezét .
  • a return utasítás is kihagyható, mert ez a lezárás várhatóan egy kifejezés eredményét adja vissza.

annak ellenére, hogy a fenti kódminta Double típusokat használ, nem korlátozódik ezekre a típusokra. Az eredményül kapott map() függvény típusa más típusú lehet, mint amit beletesz, és használhatja a map() – et a Dictionary – en is.

lépjünk tovább reduce(_:_:)!

a

Reduce függvény használata a reduce(_:_:) függvény a gyűjtemény minden elemére hurkol, és egy értékre csökkenti őket. Gondolj arra, hogy több értéket egyesít egybe.

a reduce funkció talán a legnehezebb térkép, reduce, filter megérteni. Hogyan lehet az értékek gyűjteményéből egy értékbe menni?

néhány példa:

  • több érték összegének létrehozása, azaz 3 + 4 + 5 = 12
  • karakterláncok gyűjteményének összefűzése, azaz = "Zaphod, Trillian, Ford"
  • egy értékkészlet átlagolása, azaz.(7 + 3 + 10) / 3 = 7/3 + 3/3 + 10/3 = 6.667

az adatfeldolgozás során rengeteg forgatókönyvet el lehet képzelni, amikor az ilyen egyszerű műveletek jól jönnek. Mint korábban, bármelyik problémát meg lehet oldani egy for-hurokkal, de a reduce(_:_:) egyszerűen rövidebb és gyorsabb.

itt van, hogyan:

let értékek =
let összeg = értékek.kicsinyítés (0,+)
nyomtatás (összeg)
figyelmeztetések elrejtése

a reduce(_:_:) függvény két argumentumot tartalmaz, egy kezdeti értéket és egy lezárást. A fenti kódban a + operátort adjuk meg, amely szintén két paraméterrel rendelkező függvény.

természetesen saját lezárást is biztosíthat:

let értékek =
let átlag = értékek.csökkentés (0.0) { $0 + $1 } / kettős (értékek.szám)
nyomtatás (átlag)
figyelmeztetések elrejtése

a fenti példában három szám átlagát számítja ki. A kódban szereplő értékek mindegyike Double. Először összeadjuk az összes számot, majd elosztjuk a számok mennyiségével.

a reduce(_:_:) funkció kétféleképpen különbözik:

  1. a reduce(_:_:) függvénynek két meg nem nevezett paramétere van; a kezdeti érték, valamint a
  2. a reduce(_:_:) – nek biztosított lezárásnak két paramétere is van; a csökkentés jelenlegi eredménye, valamint az új érték, amely hamarosan csökken

itt nézd meg ezt:

let értékek =
let összeg = értékek.kicsinyítés (0) {
nyomtatás(“\($0) + \($1) = \($0 + $1)”)
vissza $0 + $1
}
nyomtatás (összeg)
elrejtése figyelmeztetések

a fenti példában, akkor tisztán látni és , a 2 paraméter a lezárások. A kód futtatásakor ezt a kimenetet kapja:

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

látod, hogyan kezdjük 0, majd hozzáadjuk 7? A következő lépésben vesszük a 7 értéket – az aktuális csökkentési értéket–, majd hozzáadjuk a 3 értéket, a “következő” értéket a csökkentéshez.

itt van egy másik módja annak, hogy megnézzük:

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

ez azt is világossá teszi, hogy miért van szükség a reduce(_:_:) kezdeti értékére, mert ez a Bezárás első első paramétere.

a csökkentés bonyolult lehet. Fontos megérteni, hogy iteratív módon alkalmaz egy műveletet, például +, egy értékkészletre, amíg csak egy érték marad. Szó szerint csökkenti az értékek mennyiségét.

lépjünk tovább filter(_:)!

a

szűrőfunkció használata a filter függvény egy gyűjtemény minden elemére hurkol, és olyan gyűjteményt ad vissza, amely csak olyan elemeket tartalmaz, amelyek megfelelnek egy include feltételnek.

ez olyan, mintha egy if – utasítást alkalmaznánk egy gyűjteményre, és csak azokat az értékeket tartanánk meg, amelyek megfelelnek a feltételnek.

itt, nézd meg ezt:

legyen értékek =
legyen még = értékek.szűrő { $0.isMultiple (nak, – nek: 2) }
nyomtatás (még)
figyelmeztetések elrejtése

a fenti példában a values páros számokat szűri. A isMultiple(of:) függvény true értéket ad vissza, ha az osztható 2 – val, egyébként pedig false – vel.

a map(_:) és reduce(_:_:) – től eltérően a filter(_:) zárásnak logikai értéket kell adnia, tehát vagy truevagy false. Amikor a Bezárás true értéket ad vissza, az érték megmarad, a false visszatérésekor pedig az érték elhagyásra kerül. Így szűri a filter(_:) a bemeneti tömböt.

itt egy kicsit világosabb példa, a lezárás kibővült:

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

a példában a lezárás logikai értéket ad vissza, amelyet -> Booljelöl. Egy paramétert ad meg, a gyűjtemény elemét, és a isMultiple(of:) eredményt adja vissza. Ügyes!

Map, Reduce és Filter

kombinálhatja a map(), reduce() és filter() funkciókat? Dehogynem!

tegyük fel, hogy van egy osztály a diákok. Tudod, az év minden diák született. A 2000-ben vagy azt követően született összes hallgató összesített életkorát szeretné kiszámítani.

itt van, hogyan kell csinálni, hogy:

legyen most = 2020
legyen évek =
legyen összeg = évek.szűrő({ $0 >= 2000 }).térkép ({ most – $0}).kicsinyítés (0,+)
nyomtatás (összeg)
figyelmeztetések elrejtése

a fenti kódminta láncolást használ. Az egyik függvény eredményét használja bemenetként a másikhoz, kombinálva a map-reduce-filter-t. A map() függvényt a filter() függvény eredmény tömbjén, a reduce() függvényt pedig a map() függvény eredményén hívják meg. Király!

maga a kód egyszerű:

  1. készítsünk egy állandó now és years értéket, és adjunk hozzá egy csomó évet.
  2. szűrje ki a 2000 alatti éveket, azaz. tartsa meg azokat, amelyeknél a >= 2000 true
  3. minden évben átalakul egy korba, kivonva az évet a now
  4. – ből, az összes életkor hozzáadásával, a +

Vegyünk egy érdekesebb példát. Nézze meg a következő kódot, amelyet a FizzBuzz oktatóanyagából vettek:

legyen fizzbuzz: (Int) -> String = { i in
kapcsoló (i % 3 = = 0, i % 5 == 0)
{
case (true, false):
return “Fizz”
case (false, true):
return “Buzz”
case (true, True):
return “FizzBuzz”
default:
return ” \(i)”
}
}
hagyja eredmény = tömb (2…100).térkép(fizzbuzz).csökkentés(“1”, { $0 + “, ” + $1 })
nyomtatás (eredmény)
figyelmeztetések elrejtése

nézze meg, mi folyik itt? Egy tömböt 2-től 100-ig terjedő számokkal alakítunk át “Fizz”, “Buzz” vagy “FizzBuzz” – ra map(_:) – vel, a játék szabályai alapján. Végül a karakterláncok tömbjét egy nagy karakterláncra redukáljuk reduce(_:_:) – vel, minden értéket egyesítve. Ügyes!

további olvasmányok

mi lenne, ha mindezt for in hurkokkal kellene kódolni? Sokkal több kódot használnál. És ez a map-reduce-filter ereje: tömörebb, gyakran könnyebben olvasható, és — valld be-nagyon rohadt jó!

szeretne többet megtudni? Nézze meg ezeket az erőforrásokat:

  • hogyan kell használni a” hol ” a Swift
  • FlatMap és CompactMap magyarázata Swift
  • a végső útmutató a lezárások Swift
  • hogyan: keressen egy elemet egy tömbben Swift
  • Játssz Kód: Bináris keresés Swift
  • első lépések Xcode Playgrounds

jelentkezz iOS fejlesztőként

Tanuld meg, hogyan építhetsz iOS 14 alkalmazásokat a Swift 5 segítségével

regisztrálj a My iOS development course-ra, és tanuld meg, hogyan kezdheted el karriered professzionális iOS fejlesztőként.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.