Obținerea unor părți din colecții
Uneori nu ai nevoie de un tablou întreg. Ai nevoie de o parte din el: un interval de elemente, primele sau ultimele câteva, bucăți de dimensiuni egale sau o fereastră mobilă de vecini.
Tablourile au o singură metodă pentru toate acestea: slice(). words.slice(low, high) dă elementele de la indicele low până la, dar fără, indicele high. Omite high ca să mergi până la sfârșit. Un indice negativ se numără înapoi de la sfârșit.
arr.slice(low, high)— de la indicelelowpână la, dar fără,higharr.slice(0, n)— primelenelementearr.slice(n)— tot de la indicelenpână la sfârșitarr.slice(-n)— ultimelenelemente
slice() construiește întotdeauna un tablou nou și copiază în el elementele alese. Modificarea copiei nu modifică originalul, iar modificarea originalului nu modifică copia. În alte limbaje aceeași operație dă o vedere care împarte memoria cu originalul — aici asta nu se întâmplă niciodată.
Nu există take, drop, chunked sau windowed încorporate. Pentru aceste sarcini, lecția de față folosește slice() cu limite calculate, o buclă for sau o mică funcție generică ajutătoare.
Majoritatea exemplelor din această pagină folosesc aceleași date: cuvintele one two three four five six.
Slice
A tăia (slice) înseamnă a lua elementele de la anumite poziții alese.
Pentru o serie de poziții vecine, folosește slice(): words.slice(1, 4) dă elementele de la indicii 1, 2 și 3. Ține minte că indicele final este exclus: ca să obții elementele de la indicii 1 până la 3 scrii slice(1, 4).
slice() nu poate sări peste elemente. Ca să iei fiecare al doilea element sau elementele de la pozițiile pe care le enumeri tu, folosește o buclă for sau map() peste un tablou de indici.
Tăierea unui interval
words.slice(1, 4) începe la indicele 1 și se oprește înainte de indicele 4. Rezultatul are 3 elemente: [ 'two', 'three', 'four' ]. Este un tablou nou, așa că o modificare a lui nu ar atinge words.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three", "four", "five", "six"]
// indicii 1, 2 și 3 - indicele final 4 nu este inclus
const part = words.slice(1, 4)
console.log(part)
Tăiere cu pas
Ca să iei fiecare al doilea element, o buclă for cu i += 2 vizitează indicii 0, 2 și 4 și adună cuvintele. words.filter((_, i) => i % 2 === 0) dă același rezultat, dar se uită la fiecare element în loc să sară peste ele.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three", "four", "five", "six"]
// ia fiecare al doilea element de la indicele 0 până la indicele 4
const part: string[] = []
for (let i = 0; i <= 4; i += 2) {
part.push(words[i])
}
console.log(part)
Tăiere după o listă de indici
Pozițiile 3, 5 și 0 sunt păstrate într-un tablou de numere. map() alege cuvântul de la fiecare poziție, așa că rezultatul iese în ordinea indicilor.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three", "four", "five", "six"]
const indices = [3, 5, 0]
// alege elementele de la pozițiile date, în acea ordine
const part = indices.map(i => words[i])
console.log(part)
Take și Drop
Take înseamnă a păstra un număr de elemente de la un capăt. Drop înseamnă a arunca un număr de elemente de la un capăt și a păstra restul.
Ambele sunt apeluri slice(). words.slice(0, 3) ia primele 3 elemente, iar words.slice(-3) ia ultimele 3. words.slice(1) elimină primul element, iar words.slice(0, -5) elimină ultimele 5.
Există și versiuni condiționale: takeWhile, takeLastWhile, dropWhile și dropLastWhile. Acestea nu numără elemente. Ele merg de la un capăt și se opresc la primul element care nu trece o condiție. Nu există versiuni încorporate, așa că o mică funcție generică ajutătoare face treaba: găsește indicele la care condiția nu mai este îndeplinită și returnează slice() de la acel indice.
Ia primele sau ultimele n elemente
words.slice(0, 3) păstrează primele 3 cuvinte. words.slice(-3) păstrează ultimele 3, pentru că un start negativ se numără înapoi de la sfârșit.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three", "four", "five", "six"]
const first3 = words.slice(0, 3) // primele 3 elemente
const last3 = words.slice(-3) // ultimele 3 elemente
console.log(first3)
console.log(last3)
Elimină primele sau ultimele n elemente
words.slice(1) sare peste primul cuvânt. words.slice(0, -5) sare peste ultimele 5 cuvinte, așa că rămâne doar one.
Ieșire: program TypeScript și rezultatul capturat
const words = ["one", "two", "three", "four", "five", "six"]
const withoutFirst = words.slice(1) // elimină primul element
const withoutLast5 = words.slice(0, -5) // elimină ultimele 5 elemente
console.log(withoutFirst)
console.log(withoutLast5)
Ia cât timp o condiție se menține
takeWhile păstrează cuvintele de la început până când întâlnește un cuvânt care începe cu f. takeLastWhile păstrează cuvintele de la sfârșit până când întâlnește three. startsWith() verifică începutul unui șir de caractere.
Ieșire: program TypeScript și rezultatul capturat
// takeWhile păstrează elementele de la început cât timp keep() spune da, apoi se oprește.
function takeWhile<T>(items: T[], keep: (item: T) => boolean): T[] {
for (let i = 0; i < items.length; i++) {
if (!keep(items[i])) return items.slice(0, i)
}
return items.slice()
}
// takeLastWhile păstrează elementele de la sfârșit cât timp keep() spune da, apoi se oprește.
function takeLastWhile<T>(items: T[], keep: (item: T) => boolean): T[] {
for (let i = items.length - 1; i >= 0; i--) {
if (!keep(items[i])) return items.slice(i + 1)
}
return items.slice()
}
const words = ["one", "two", "three", "four", "five", "six"]
const fromStart = takeWhile(words, s => !s.startsWith("f"))
const fromEnd = takeLastWhile(words, s => s !== "three")
console.log(fromStart)
console.log(fromEnd)
Elimină cât timp o condiție se menține
dropWhile sare peste cuvintele de 3 litere de la început și păstrează tot de la three înainte. dropLastWhile sare peste cuvintele de la sfârșit cât timp ele conțin litera i. includes() verifică dacă un șir de caractere conține o bucată de text.
Ieșire: program TypeScript și rezultatul capturat
// dropWhile sare peste elementele de la început cât timp skip() spune da și păstrează restul.
function dropWhile<T>(items: T[], skip: (item: T) => boolean): T[] {
for (let i = 0; i < items.length; i++) {
if (!skip(items[i])) return items.slice(i)
}
return []
}
// dropLastWhile sare peste elementele de la sfârșit cât timp skip() spune da și păstrează restul.
function dropLastWhile<T>(items: T[], skip: (item: T) => boolean): T[] {
for (let i = items.length - 1; i >= 0; i--) {
if (!skip(items[i])) return items.slice(0, i + 1)
}
return []
}
const words = ["one", "two", "three", "four", "five", "six"]
const fromStart = dropWhile(words, s => s.length === 3)
const fromEnd = dropLastWhile(words, s => s.includes("i"))
console.log(fromStart)
console.log(fromEnd)
Chunked
Fragmentarea înseamnă tăierea unui tablou în bucăți de aceeași dimensiune. Ultima bucată poate fi mai scurtă atunci când elementele nu se împart uniform.
Nu există o metodă încorporată de fragmentare, dar funcția ajutătoare este scurtă: parcurge tabloul cu i += size și adaugă de fiecare dată items.slice(i, i + size). slice() nu citește niciodată dincolo de sfârșitul tabloului, așa că ultima bucată scurtă iese corect de la sine.
Rezultatul este un tablou de tablouri, iar fiecare bucată își păstrează propriile paranteze. Node.js afișează acest rezultat pe o singură linie: [ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ], [ 9, 10, 11 ], [ 12, 13 ] ].
Ca să lucrezi imediat pe fiecare bucată, înlănțuie un map() peste bucăți.
Împărțire în bucăți de 3
Numerele de la 0 la 13 sunt tăiate în bucăți de 3. Ultima bucată are doar 2 elemente: [ 12, 13 ].
Ieșire: program TypeScript și rezultatul capturat
// chunked taie un tablou în bucăți de size elemente; ultima bucată poate fi mai scurtă.
function chunked<T>(items: T[], size: number): T[][] {
const result: T[][] = []
for (let i = 0; i < items.length; i += size) {
result.push(items.slice(i, i + size))
}
return result
}
const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
const chunks = chunked(numbers, 3)
console.log(chunks)
Suma fiecărei bucăți
Aceleași bucăți, dar fiecare este adunată cu reduce(). Se păstrează doar sumele: [ 3, 12, 21, 30, 25 ].
Ieșire: program TypeScript și rezultatul capturat
// chunked taie un tablou în bucăți de size elemente; ultima bucată poate fi mai scurtă.
function chunked<T>(items: T[], size: number): T[][] {
const result: T[][] = []
for (let i = 0; i < items.length; i += size) {
result.push(items.slice(i, i + size))
}
return result
}
const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
// adună fiecare bucată de 3
const sums = chunked(numbers, 3).map(chunk => chunk.reduce((a, b) => a + b, 0))
console.log(sums)
Windowed
O fereastră este un grup de elemente vecine. Ferestruirea deplasează grupul de-a lungul tabloului și adună fiecare poziție. Spre deosebire de bucăți, ferestrele se suprapun.
Nu există un windowed încorporat. O buclă for cu items.slice(i, i + size) face asta. O mică funcție generică ajutătoare windowed o face reutilizabilă. Cu un step, fereastra se deplasează cu mai multe poziții deodată. Cu partial setat pe true, o fereastră mai scurtă de la sfârșit este păstrată în loc să fie aruncată.
O fereastră de 2 care se deplasează cu 1 pas este același lucru cu împerecherea fiecărui element cu următorul. Asta este o buclă care se oprește cu un element înainte de sfârșit.
Ferestre de 3
Fereastra are 3 cuvinte și se deplasează cu o poziție de fiecare dată. Bucla se oprește când o fereastră completă nu mai încape, așa că sunt 3 ferestre. Rezultatul este un tablou de tablouri, iar Node.js îl afișează pe mai multe linii, câte o fereastră pe linie.
Ieșire: program TypeScript și rezultatul capturat
// windowed returnează fiecare grup de size elemente, deplasându-se cu un pas pe rând.
function windowed<T>(items: T[], size: number): T[][] {
const result: T[][] = []
for (let i = 0; i + size <= items.length; i++) {
result.push(items.slice(i, i + size))
}
return result
}
const numbers = ["one", "two", "three", "four", "five"]
console.log(windowed(numbers, 3))
Ferestre cu pas și ferestre parțiale
Fereastra are 3 numere și se deplasează cu 2 poziții de fiecare dată. Pentru că partial este true, ultima fereastră [ 9, 10 ] este păstrată chiar dacă este scurtă.
Ieșire: program TypeScript și rezultatul capturat
// windowed returnează grupuri de size elemente, deplasându-se cu step poziții de fiecare dată.
// Cu partial = true, se păstrează și un grup mai scurt la sfârșit.
function windowed<T>(items: T[], size: number, step: number, partial: boolean): T[][] {
const result: T[][] = []
for (let i = 0; i < items.length; i += step) {
let end = i + size
if (end > items.length) {
if (!partial) break
end = items.length
}
result.push(items.slice(i, end))
}
return result
}
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(windowed(numbers, 3, 2, true))
Suma fiecărei ferestre
Fiecare fereastră de 3 vecini este adunată cu reduce(). Se păstrează doar sumele: [ 6, 9, 12 ].
Ieșire: program TypeScript și rezultatul capturat
const numbers = [1, 2, 3, 4, 5]
// adună fiecare fereastră de 3 vecini
const sums: number[] = []
for (let i = 0; i + 3 <= numbers.length; i++) {
const nextThree = numbers.slice(i, i + 3)
sums.push(nextThree.reduce((a, b) => a + b, 0))
}
console.log(sums)
Împerecherea fiecărui element cu următorul
Prima buclă construiește o pereche din fiecare cuvânt și vecinul său. O pereche este un tuplu, tipul [string, string]. A doua buclă compară aceiași vecini și reține dacă primul cuvânt este mai lung decât al doilea.
Ieșire: program TypeScript și rezultatul capturat
// O pereche conține două elemente vecine.
type Pair = [string, string]
const letters = ["one", "two", "three", "four", "five"]
// fiecare element împreună cu cel de după el
const pairs: Pair[] = []
for (let i = 0; i + 1 < letters.length; i++) {
pairs.push([letters[i], letters[i + 1]])
}
console.log(pairs)
// aceeași parcurgere, dar se compară lungimile vecinilor
const longer: boolean[] = []
for (let i = 0; i + 1 < letters.length; i++) {
longer.push(letters[i].length > letters[i + 1].length)
}
console.log(longer)