írta: Reinder de Vries, július 9, 2020 in App Development, 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!
- Bevezetés a térképbe, Csökkentésbe és szűrésbe
- gyors indítás: Magasabb rendű funkciók a Swift-ben
- a térkép funkció használata
- a Csökkentés funkció használata
- a szűrő funkció használata
- a térkép, a csökkentés és a szűrő kombinálása
- 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, amelyekif
-utasításon mentek keresztül, és csak akkor, ha ez a feltételtrue
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, mintmap(_:)
, 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 amap(_:)
, azzal a különbséggel, hogy eltávolítja anil
é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önbenfalse
-
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 afirst(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 fahrenheit = celsius.térkép { $0 * (9/5) + 32 }
print (fahrenheit)
akkor is csinálni minden, hogy egy sorban:
.map { * (9/5) + 32 }
mi történik itt?
- a konstans
celsius
definiálva van, páros tömbként, és néhány véletlenszerű Celsius értékkel inicializálva. - a
map(_:)
függvényt acelsius
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. - 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 Double
tí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 egyDouble
paramétert használ bemenetként, és várhatóanDouble
értéket ad vissza. Most, hogy kihagyta avalue
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 összeg = értékek.kicsinyítés (0,+)
nyomtatás (összeg)
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 átlag = értékek.csökkentés (0.0) { $0 + $1 } / kettős (értékek.szám)
nyomtatás (átlag)
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:
- a
reduce(_:_:)
függvénynek két meg nem nevezett paramétere van; a kezdeti érték, valamint a - 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 összeg = értékek.kicsinyítés (0) {
nyomtatás(“\($0) + \($1) = \($0 + $1)”)
vissza $0 + $1
}
nyomtatás (összeg)
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 még = értékek.szűrő { $0.isMultiple (nak, – nek: 2) }
nyomtatás (még)
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 true
vagy 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 -> Bool
jelö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 évek =
legyen összeg = évek.szűrő({ $0 >= 2000 }).térkép ({ most – $0}).kicsinyítés (0,+)
nyomtatás (összeg)
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ű:
- készítsünk egy állandó
now
ésyears
értéket, és adjunk hozzá egy csomó évet. - szűrje ki a 2000 alatti éveket, azaz. tartsa meg azokat, amelyeknél a
>= 2000
true
- minden évben átalakul egy korba, kivonva az évet a
now
- – 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:
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)
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.