Transformarea unei colecții
O transformare ia o colecție, cum ar fi un tablou sau un Map, și construiește din ea o colecție nouă. Colecția originală nu este modificată.
Tablourile din TypeScript au deja majoritatea acestor operații ca metode: map, filter, flat, flatMap și join. Le apelezi pe tablou și primești înapoi o valoare nouă, deci nu este nevoie de nicio buclă. Câteva operații, precum zip, nu au o metodă încorporată — pentru acestea scrii o dată o mică funcție ajutătoare și o refolosești.
O funcție ajutătoare poate fi generică. O funcție generică lucrează cu orice tip de element: scrii o dată function zip<A, B>(first: A[], second: B[]): [A, B][] și o folosești la fel pentru numere, șiruri de caractere și obiecte. Parametrii de tip A și B sunt completați de compilator la locul apelului.
Map
Operația map aplică aceeași funcție fiecărui element și adună răspunsurile într-un tablou nou, de aceeași lungime. De exemplu, poate transforma [ 1, 2, 3 ] în [ 3, 6, 9 ].
Tablourile au o metodă map încorporată. Îi dai o funcție, iar ea returnează tabloul nou. Tipul rezultatului urmează funcția: dacă funcția returnează un string, primești un string[].
Nu confunda acest lucru cu clasa Map, care păstrează perechi de chei și valori. Aici „map” înseamnă „aplică o funcție fiecărui element”.
Transformarea fiecărui element
numbers.map(x => x * 3) apelează funcția pentru fiecare element și returnează un tablou nou. Tabloul original numbers este afișat și el, ca să se vadă că mai conține [ 1, 2, 3 ].
Ieșire: program TypeScript și rezultatul capturat
const numbers = [1, 2, 3]
// map apelează funcția o dată pentru fiecare element
const tripled = numbers.map(x => x * 3)
console.log(numbers)
console.log(tripled)
Transformarea cu indicele
Uneori contează și poziția unui element. Funcția dată lui map primește indicele ca al doilea argument, deci le poți folosi pe amândouă. Aici fiecare valoare este înmulțită cu propriul ei indice, iar primul element devine 0.
Ieșire: program TypeScript și rezultatul capturat
const numbers = [1, 2, 3]
// al doilea argument al funcției de apel este poziția elementului
const result = numbers.map((value, idx) => value * idx)
console.log(result)
Omiterea unor rezultate
Uneori unele rezultate trebuie eliminate. Lasă funcția să returneze undefined pentru acele elemente, apoi elimină-le cu filter. Funcția ajutătoare isDefined este o gardă de tip: tipul ei de retur value is T îi spune compilatorului că orice valoare care trece de filtru nu mai este undefined. Astfel tipul rezultatului se restrânge de la (number | undefined)[] la number[].
Ieșire: program TypeScript și rezultatul capturat
const numbers = [1, 2, 3]
// funcția returnează undefined pentru elementele pe care vrem să le eliminăm
const maybe = numbers.map(x => (x === 2 ? undefined : x * 3))
// o gardă de tip îi spune compilatorului că valorile păstrate nu sunt niciodată undefined
function isDefined<T>(value: T | undefined): value is T {
return value !== undefined
}
const result: number[] = maybe.filter(isDefined)
console.log(maybe)
console.log(result)
Transformarea cheilor
Pentru a schimba cheile unui Map, desfășoară-l într-un tablou de perechi [key, value] cu [...numbersMap], transformă fiecare pereche într-o pereche nouă și dă rezultatul lui new Map(...). Aici toUpperCase() schimbă fiecare cheie. Un Map își păstrează intrările în ordinea inserării, deci rezultatul este mereu în aceeași ordine.
Ieșire: program TypeScript și rezultatul capturat
const numbersMap = new Map([["key1", 1], ["key2", 2]])
// desfășoară Map-ul în perechi, schimbă fiecare cheie, construiește un Map nou
const upperKeys = new Map(
[...numbersMap].map(([key, value]): [string, number] => [key.toUpperCase(), value])
)
console.log(numbersMap)
console.log(upperKeys)
Transformarea valorilor
Pentru a schimba valorile, procedează la fel, dar păstrează cheia și calculează o valoare nouă. Aici fiecare valoare crește cu lungimea cheii ei: 1 + "key1".length este 5.
Ieșire: program TypeScript și rezultatul capturat
const numbersMap = new Map([["key1", 1], ["key2", 2]])
// păstrează cheia, calculează o valoare nouă
const newValues = new Map(
[...numbersMap].map(([key, value]): [string, number] => [key, value + key.length])
)
console.log(newValues)
Zip
Zip ia două tablouri și le împerechează elementele după poziție: primul cu primul, al doilea cu al doilea și așa mai departe. Rezultatul are atâtea perechi câte elemente are tabloul mai scurt.
Nu există o metodă zip încorporată, așa că o mică funcție ajutătoare este răspunsul obișnuit. O pereche se scrie ca tip tuplu, [A, B]: un tablou de lungime fixă în care fiecare poziție are propriul ei tip. Află lungimea mai mică cu Math.min și parcurge cu un indice pentru a construi perechile.
Împerecherea a două tablouri
Funcția generică zip returnează aici un [string, string][]: un tablou de tupluri cu două elemente. Bucla rulează până la lungimea mai mică și construiește un tuplu pentru fiecare indice. Afișarea arată fiecare pereche ca pe un mic tablou propriu.
Ieșire: program TypeScript și rezultatul capturat
// zip formează perechi de elemente după poziție și se oprește la tabloul mai scurt
function zip<A, B>(first: A[], second: B[]): [A, B][] {
const n = Math.min(first.length, second.length)
const pairs: [A, B][] = []
for (let i = 0; i < n; i++) {
pairs.push([first[i], second[i]])
}
return pairs
}
const colors = ["roșu", "maro", "gri"]
const animals = ["lup", "urs", "vultur"]
const pairs = zip(colors, animals)
console.log(pairs)
Împerecherea cu o transformare
Nu ai nevoie mereu de perechile în sine. Aici bucla folosește direct ambele elemente pentru a construi o propoziție. animals[i][0] este prima literă, scrisă cu majusculă prin toUpperCase(), iar animals[i].slice(1) este restul cuvântului. Propoziția este construită cu un șir șablon.
Ieșire: program TypeScript și rezultatul capturat
const colors = ["roșu", "maro", "gri"]
const animals = ["lup", "urs", "vultur"]
const n = Math.min(colors.length, animals.length)
for (let i = 0; i < n; i++) {
// scrie cu majusculă doar prima literă a numelui animalului
const name = animals[i][0].toUpperCase() + animals[i].slice(1)
console.log(`${name} este ${colors[i]}`)
}
Desfacerea unui tablou de perechi
Desfacerea este operația inversă: un tablou de perechi devine două tablouri. Bucla for...of destructurează fiecare tuplu în word și value și adaugă părțile în două tablouri separate.
Ieșire: program TypeScript și rezultatul capturat
const numberPairs: [string, number][] = [["one", 1], ["two", 2], ["three", 3]]
const words: string[] = []
const values: number[] = []
// destructurarea dă un nume fiecărei părți a perechii
for (const [word, value] of numberPairs) {
words.push(word)
values.push(value)
}
console.log(words)
console.log(values)
Asociere
Asocierea construiește un Map dintr-un tablou. Fiecare element îți dă o cheie și o valoare. Un Map nu poate păstra de două ori aceeași cheie, deci dacă două elemente produc aceeași cheie, câștigă cel de mai târziu.
Calea scurtă este să transformi cu map fiecare element într-un tuplu [key, value] și să dai acel tablou lui new Map(...). Scrie tipul de retur al funcției ca [string, number], pentru ca compilatorul să vadă un tuplu și nu un tablou obișnuit.
Elementele ca chei
Elementul însuși devine cheia, iar valoarea este calculată din el. Aici cuvintele sunt chei, iar lungimile lor sunt valori, deci lengths.get("three") este 5.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three"]
// fiecare cuvânt devine cheie, lungimea lui devine valoare
const lengths = new Map(words.map((word): [string, number] => [word, word.length]))
console.log(lengths)
console.log(lengths.get("three"))
Elementele ca valori
Elementul devine valoarea, iar cheia este calculată din el. Aici cheia este prima literă scrisă cu majusculă. Atât two, cât și three încep cu T, deci three îl înlocuiește pe two, iar dimensiunea Map-ului este 2.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three"]
// cheia este prima literă; un cuvânt de mai târziu îl înlocuiește pe unul anterior
const byFirstLetter = new Map(
words.map((word): [string, string] => [word[0].toUpperCase(), word])
)
console.log(byFirstLetter)
console.log(byFirstLetter.size)
Calcularea și a cheii, și a valorii
Poți calcula din element atât cheia, cât și valoarea. Aici cheia este prima literă, iar valoarea este lungimea cuvântului. Din nou câștigă intrarea T de mai târziu, deci T păstrează 5, lungimea lui three.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three"]
// cheia este prima literă, valoarea este lungimea cuvântului
const lengthByLetter = new Map(
words.map((word): [string, number] => [word[0].toUpperCase(), word.length])
)
console.log(lengthByLetter)
Cheia și valoarea dintr-un singur element
Uneori un singur element conține ambele părți. split(" ") taie numele complet la spațiu într-un tablou de cuvinte. Numele de familie devine cheia, iar prenumele devine valoarea.
Ieșire: program TypeScript și rezultatul capturat
const names = ["Alice Adams", "Brian Brown"]
// un singur element conține ambele părți: nume de familie -> prenume
const byLastName = new Map(
names.map((fullName): [string, string] => {
const parts = fullName.split(" ")
return [parts[1], parts[0]]
})
)
console.log(byLastName)
Aplatizare
Aplatizarea transformă o colecție imbricată, cum ar fi un tablou de tablouri, într-un singur tablou simplu, cu toate elementele în ordine.
Tablourile au două metode pentru asta. flat() aplatizează un nivel al unui tablou de tablouri existent. flatMap(f) face ambii pași deodată: transformă fiecare element într-un tablou și apoi aplatizează rezultatele, ceea ce este util când tablourile interioare ies chiar din elemente.
Aplatizarea unui tablou de tablouri
numberSets.flat() copiază elementele fiecărui tablou interior într-un tablou nou. Două tablouri interioare de câte trei numere devin un singur tablou de șase.
Ieșire: program TypeScript și rezultatul capturat
const numberSets = [[1, 2, 3], [4, 5, 6]]
// flat() copiază elementele fiecărui tablou interior într-un singur tablou nou
const result = numberSets.flat()
console.log(result)
console.log(result.length)
Aplatizarea valorilor din obiecte
Fiecare obiect Container păstrează un tablou în câmpul său values. flatMap(c => c.values) citește acel câmp pentru fiecare container și unește toate tablourile într-unul singur. Cele opt valori din cele trei containere ajung împreună și sunt afișate unite cu virgule, ca să încapă pe o singură linie.
Ieșire: program TypeScript și rezultatul capturat
interface Container {
values: string[]
}
const containers: Container[] = [
{ values: ["one", "two", "three"] },
{ values: ["four", "five"] },
{ values: ["six", "seven", "eight"] }
]
// flatMap transformă fiecare element într-un tablou și aplatizează rezultatele
const allValues = containers.flatMap(c => c.values)
console.log(allValues.length)
console.log(allValues.join(", "))
Reprezentarea ca text
Adesea vrei să arăți o colecție ca text lizibil, de exemplu cu virgule între elemente.
Metoda join primește un separator și returnează un singur șir de caractere. Ea transformă fiecare element în text pentru tine, deci numerele nu au nevoie de niciun pas în plus. join nu are alte opțiuni în afară de separator, așa că extrele — un prefix, un sufix, o limită sau o transformare — se fac în jurul ei: cu +, cu slice sau cu un map înainte de unire.
Unirea cu un separator
words.join(", ") pune ", " între cuvinte și returnează un singur șir de caractere.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three"]
// join pune separatorul între elemente
console.log(words.join(", "))
Adăugarea unui prefix și a unui sufix
Un prefix și un sufix sunt doar text în jurul rezultatului unit. Le adaugi cu +.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three"]
// un prefix și un sufix sunt doar text în jurul rezultatului unit
const text = "început: " + words.join(" | ") + ": sfârșit"
console.log(text)
Limitarea numărului de elemente
Pentru un tablou lung poate vrei să arăți doar primele câteva elemente. Ia primele 10 cu numbers.slice(0, 10) și unește-le — join transformă singură numerele în text. Apoi adaugă ", <...>" la final, ca să arăți că au fost tăiate și alte elemente.
Ieșire: program TypeScript și rezultatul capturat
const numbers: number[] = []
for (let i = 1; i <= 100; i++) {
numbers.push(i)
}
// slice ia primele 10 elemente; join transformă numerele în text
const limit = 10
const shown = numbers.slice(0, limit).join(", ")
const text = numbers.length > limit ? shown + ", <...>" : shown
console.log(text)
Transformarea fiecărui element înainte de unire
Pentru a schimba fiecare element înainte de unire, aplică mai întâi map pe tablou și apelează join pe rezultat. Aici fiecare cuvânt devine "Element: " plus cuvântul scris cu majuscule.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three"]
// schimbă mai întâi fiecare element, apoi unește rezultatele
const parts = words.map(word => "Element: " + word.toUpperCase())
console.log(parts.join(", "))