Kurs JavaScript i TypeScript · Moduł 2: Funkcje, tablice i obiekty

Tworzenie i manipulacja tablicami w JavaScript

16 min czytania
W tej lekcji9

Witaj ponownie w Parku Jurajskim! Dzisiaj będziemy zajmować się tablicami w JavaScript - strukturami danych, które są niezbędne do zarządzania kolekcjami obiektów, takich jak nasze gatunki dinozaurów, wyniki badań genetycznych czy dane z systemów monitorowania parku.

Czym są tablice?

Tablice to uporządkowane kolekcje elementów, które mogą przechowywać dane dowolnego typu. Można je porównać do szafek laboratoryjnych, gdzie każda szuflada (indeks tablicy) zawiera konkretną próbkę (element tablicy). Każdy element ma swój unikalny numer pozycji (indeks), który rozpoczyna się od 0.

Tworzenie tablic

W JavaScript istnieje kilka sposobów tworzenia tablic:

1. Literał tablicowy (najczęściej używany)

Najpopularniejszym sposobem jest użycie nawiasów kwadratowych []:

1// Tablica gatunków dinozaurów w naszym parku
2const dinosaurs = ["Tyrannosaurus", "Velociraptor", "Triceratops", "Brachiosaurus"];
3
4// Tablica mieszanych typów danych (liczby, stringi, booleany)
5const dinoData = ["Blue", 5, true, 120.5];
6
7// Pusta tablica, do której będziemy dodawać elementy później
8const dinoEnclosures = [];

2. Konstruktor Array

Możemy również użyć konstruktora Array():

1// Tablica utworzona za pomocą konstruktora
2const parkSectors = new Array("A", "B", "C", "D", "E");
3
4// Tablica z predefiniowaną długością, ale bez wartości
5const securityReadings = new Array(10); // Tworzy tablicę z 10 pustymi elementami
6
7// Uwaga: jeśli przekażemy tylko jedną liczbę, tworzy to tablicę o tej długości
8// Jeśli przekażemy wiele argumentów, tworzą one elementy tablicy
9const confusingArray = new Array(3); // Tablica o długości 3: [empty x 3]
10const normalArray = new Array(1, 2, 3); // Tablica z trzema elementami: [1, 2, 3]

3. Metoda Array.of() (ES6)

Aby uniknąć niejednoznaczności konstruktora Array(), można użyć Array.of():

1// Zawsze tworzy tablicę z przekazanymi elementami
2const weights = Array.of(5000); // [5000], a nie tablica długości 5000
3const measurements = Array.of(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

4. Metoda Array.from() (ES6)

Ta metoda tworzy tablicę z obiektów podobnych do tablicy (np. kolekcji DOM) lub iterowalnych (np. stringów):

1// Tworzenie tablicy z iterowalnego obiektu (string)
2const dinoLetters = Array.from("TREX"); // ["T", "R", "E", "X"]
3
4// Tworzenie tablicy z mapowaniem
5const dinoAges = Array.from([5, 7, 3, 10], age => age * 2); // [10, 14, 6, 20]
6
7// Przykład z kolekcją DOM (w przeglądarce)
8// const dinoElements = Array.from(document.querySelectorAll('.dinosaur'));

Dostęp do elementów tablicy

Elementy tablicy są indeksowane od 0, co oznacza, że pierwszy element ma indeks 0, drugi 1, itd.

1const velociraptors = ["Blue", "Delta", "Echo", "Charlie"];
2
3// Dostęp do pojedynczych elementów
4console.log(velociraptors[0]); // "Blue"
5console.log(velociraptors[2]); // "Echo"
6
7// Modyfikacja elementu
8velociraptors[1] = "New Delta";
9console.log(velociraptors); // ["Blue", "New Delta", "Echo", "Charlie"]
10
11// Dostęp do nieistniejącego elementu zwraca undefined
12console.log(velociraptors[10]); // undefined

Długość tablicy

Właściwość length zwraca liczbę elementów w tablicy:

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops"];
2console.log(dinosaurs.length); // 3
3
4// Możemy również modyfikować długość tablicy
5dinosaurs.length = 2;
6console.log(dinosaurs); // ["T-Rex", "Velociraptor"] - Triceratops został usunięty
7
8// Zwiększenie długości dodaje puste elementy
9dinosaurs.length = 5;
10console.log(dinosaurs); // ["T-Rex", "Velociraptor", empty x 3]

Podstawowe operacje na tablicach

Dodawanie elementów

Istnieje kilka sposobów dodawania elementów do tablicy:

1. Na końcu tablicy: push()

1const dinosaurs = ["T-Rex", "Velociraptor"];
2
3// Dodawanie na końcu
4dinosaurs.push("Triceratops");
5console.log(dinosaurs); // ["T-Rex", "Velociraptor", "Triceratops"]
6
7// push może dodać wiele elementów naraz
8dinosaurs.push("Brachiosaurus", "Stegosaurus");
9console.log(dinosaurs); // ["T-Rex", "Velociraptor", "Triceratops", "Brachiosaurus", "Stegosaurus"]
10
11// push zwraca nową długość tablicy
12const newLength = dinosaurs.push("Ankylosaurus");
13console.log(newLength); // 6

2. Na początku tablicy: unshift()

1const dinosaurs = ["Velociraptor", "Triceratops"];
2
3// Dodawanie na początku
4dinosaurs.unshift("T-Rex");
5console.log(dinosaurs); // ["T-Rex", "Velociraptor", "Triceratops"]
6
7// unshift również może dodać wiele elementów naraz
8dinosaurs.unshift("Spinosaurus", "Dilophosaurus");
9console.log(dinosaurs); // ["Spinosaurus", "Dilophosaurus", "T-Rex", "Velociraptor", "Triceratops"]
10
11// unshift także zwraca nową długość tablicy
12const newLength = dinosaurs.unshift("Compsognathus");
13console.log(newLength); // 6

3. Na konkretnej pozycji: splice()

1const dinosaurs = ["T-Rex", "Velociraptor", "Stegosaurus"];
2
3// Wstawianie elementu na pozycji 1 (jako drugi element)
4// splice(pozycja, ile_usunąć, elementy_do_dodania...)
5dinosaurs.splice(1, 0, "Triceratops");
6console.log(dinosaurs); // ["T-Rex", "Triceratops", "Velociraptor", "Stegosaurus"]
7
8// Zastępowanie elementu na pozycji 2
9dinosaurs.splice(2, 1, "Brachiosaurus");
10console.log(dinosaurs); // ["T-Rex", "Triceratops", "Brachiosaurus", "Stegosaurus"]
11
12// Możemy dodać wiele elementów naraz
13dinosaurs.splice(1, 0, "Ankylosaurus", "Dilophosaurus");
14console.log(dinosaurs); // ["T-Rex", "Ankylosaurus", "Dilophosaurus", "Triceratops", "Brachiosaurus", "Stegosaurus"]

Usuwanie elementów

Podobnie jak w przypadku dodawania, istnieje kilka metod usuwania elementów:

1. Z końca tablicy: pop()

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops"];
2
3// Usuwanie ostatniego elementu
4const removedDino = dinosaurs.pop();
5console.log(removedDino); // "Triceratops"
6console.log(dinosaurs); // ["T-Rex", "Velociraptor"]

2. Z początku tablicy: shift()

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops"];
2
3// Usuwanie pierwszego elementu
4const removedDino = dinosaurs.shift();
5console.log(removedDino); // "T-Rex"
6console.log(dinosaurs); // ["Velociraptor", "Triceratops"]

3. Z konkretnej pozycji: splice()

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
2
3// Usuwanie jednego elementu na pozycji 1
4const removedDinos = dinosaurs.splice(1, 1);
5console.log(removedDinos); // ["Velociraptor"]
6console.log(dinosaurs); // ["T-Rex", "Triceratops", "Stegosaurus"]
7
8// Usuwanie wielu elementów zaczynając od pozycji 1
9const moreRemovedDinos = dinosaurs.splice(1, 2);
10console.log(moreRemovedDinos); // ["Triceratops", "Stegosaurus"]
11console.log(dinosaurs); // ["T-Rex"]

Znalezienie elementu w tablicy

1. indexOf() i lastIndexOf()

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Velociraptor"];
2
3// Znalezienie pierwszego wystąpienia
4const firstIndex = dinosaurs.indexOf("Velociraptor");
5console.log(firstIndex); // 1
6
7// Znalezienie ostatniego wystąpienia
8const lastIndex = dinosaurs.lastIndexOf("Velociraptor");
9console.log(lastIndex); // 3
10
11// Jeśli element nie istnieje, zwraca -1
12const notFoundIndex = dinosaurs.indexOf("Spinosaurus");
13console.log(notFoundIndex); // -1

2. includes() (ES6)

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops"];
2
3// Sprawdzenie, czy element istnieje w tablicy
4const hasVelociraptor = dinosaurs.includes("Velociraptor");
5console.log(hasVelociraptor); // true
6
7const hasSpinosaurus = dinosaurs.includes("Spinosaurus");
8console.log(hasSpinosaurus); // false

3. find() i findIndex() (ES6)

Metody te są przydatne do wyszukiwania elementów złożonych (obiektów) na podstawie kryteriów:

1// Tablica obiektów dinozaurów
2const dinosaurData = [
3  { name: "Rex", species: "Tyrannosaurus", age: 16, dangerous: true },
4  { name: "Blue", species: "Velociraptor", age: 5, dangerous: true },
5  { name: "Spike", species: "Stegosaurus", age: 10, dangerous: false },
6  { name: "Trixie", species: "Triceratops", age: 18, dangerous: false }
7];
8
9// Znalezienie pierwszego dinozaura starszego niż 15 lat
10const oldDino = dinosaurData.find(dino => dino.age > 15);
11console.log(oldDino); // { name: "Rex", species: "Tyrannosaurus", age: 16, dangerous: true }
12
13// Znalezienie indeksu pierwszego bezpiecznego dinozaura
14const safeIndex = dinosaurData.findIndex(dino => !dino.dangerous);
15console.log(safeIndex); // 2 (Spike)

Kopiowanie i łączenie tablic

1. Kopiowanie tablicy za pomocą slice()

1const originalDinos = ["T-Rex", "Velociraptor", "Triceratops"];
2
3// Tworzenie kopii całej tablicy
4const dinosCopy = originalDinos.slice();
5console.log(dinosCopy); // ["T-Rex", "Velociraptor", "Triceratops"]
6
7// Kopiowanie części tablicy (od indeksu 1 do końca)
8const partialCopy = originalDinos.slice(1);
9console.log(partialCopy); // ["Velociraptor", "Triceratops"]
10
11// Kopiowanie zakresu (od indeksu 0 do 1, bez 2)
12const rangeCopy = originalDinos.slice(0, 2);
13console.log(rangeCopy); // ["T-Rex", "Velociraptor"]

2. Łączenie tablic za pomocą concat()

1const carnivores = ["T-Rex", "Velociraptor"];
2const herbivores = ["Triceratops", "Brachiosaurus", "Stegosaurus"];
3
4// Łączenie dwóch tablic
5const allDinos = carnivores.concat(herbivores);
6console.log(allDinos);
7// ["T-Rex", "Velociraptor", "Triceratops", "Brachiosaurus", "Stegosaurus"]
8
9// Można łączyć więcej tablic naraz
10const smallDinos = ["Compsognathus"];
11const allSpecies = carnivores.concat(herbivores, smallDinos);
12console.log(allSpecies);
13// ["T-Rex", "Velociraptor", "Triceratops", "Brachiosaurus", "Stegosaurus", "Compsognathus"]

3. Operator rozproszenia (spread) (ES6)

1const carnivores = ["T-Rex", "Velociraptor"];
2const herbivores = ["Triceratops", "Brachiosaurus"];
3
4// Łączenie tablic za pomocą spread
5const allDinos = [...carnivores, ...herbivores];
6console.log(allDinos); // ["T-Rex", "Velociraptor", "Triceratops", "Brachiosaurus"]
7
8// Można dodawać elementy w środku
9const mixedCollection = [...carnivores, "Dilophosaurus", ...herbivores];
10console.log(mixedCollection);
11// ["T-Rex", "Velociraptor", "Dilophosaurus", "Triceratops", "Brachiosaurus"]
12
13// Kopiowanie tablicy za pomocą spread
14const dinosCopy = [...carnivores];
15console.log(dinosCopy); // ["T-Rex", "Velociraptor"]

Przeszukiwanie i sortowanie tablic

1. Sortowanie tablicy: sort()

1const dinosaurs = ["Velociraptor", "Tyrannosaurus", "Brachiosaurus", "Ankylosaurus"];
2
3// Sortowanie alfabetyczne (domyślne)
4dinosaurs.sort();
5console.log(dinosaurs);
6// ["Ankylosaurus", "Brachiosaurus", "Tyrannosaurus", "Velociraptor"]
7
8// Sortowanie liczb (wymaga funkcji porównującej)
9const dinoWeights = [5000, 500, 15000, 7000];
10
11// Bez funkcji porównującej - nieprawidłowo sortuje liczby jako stringi
12dinoWeights.sort();
13console.log(dinoWeights); // [15000, 500, 5000, 7000] (niepoprawnie!)
14
15// Z funkcją porównującą - poprawne sortowanie rosnąco
16dinoWeights.sort((a, b) => a - b);
17console.log(dinoWeights); // [500, 5000, 7000, 15000]
18
19// Sortowanie malejąco
20dinoWeights.sort((a, b) => b - a);
21console.log(dinoWeights); // [15000, 7000, 5000, 500]

2. Sortowanie obiektów

1const dinosaurData = [
2  { name: "Rex", species: "Tyrannosaurus", age: 16 },
3  { name: "Blue", species: "Velociraptor", age: 5 },
4  { name: "Spike", species: "Stegosaurus", age: 10 },
5  { name: "Trixie", species: "Triceratops", age: 18 }
6];
7
8// Sortowanie po wieku (rosnąco)
9dinosaurData.sort((a, b) => a.age - b.age);
10console.log(dinosaurData.map(dino => `${dino.name} (${dino.age})`));
11// ["Blue (5)", "Spike (10)", "Rex (16)", "Trixie (18)"]
12
13// Sortowanie po nazwie (alfabetycznie)
14dinosaurData.sort((a, b) => a.name.localeCompare(b.name));
15console.log(dinosaurData.map(dino => dino.name));
16// ["Blue", "Rex", "Spike", "Trixie"]

3. Odwracanie kolejności: reverse()

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Brachiosaurus"];
2
3// Odwrócenie kolejności elementów
4dinosaurs.reverse();
5console.log(dinosaurs); // ["Brachiosaurus", "Triceratops", "Velociraptor", "T-Rex"]

Przekształcanie tablic

1. Konwersja na string: join()

1const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops"];
2
3// Łączenie wszystkich elementów w string z domyślnym separatorem (przecinek)
4const dinoString = dinosaurs.join();
5console.log(dinoString); // "T-Rex,Velociraptor,Triceratops"
6
7// Z niestandardowym separatorem
8const dinoList = dinosaurs.join(" | ");
9console.log(dinoList); // "T-Rex | Velociraptor | Triceratops"
10
11// Bez separatora
12const dinoNoSeparator = dinosaurs.join("");
13console.log(dinoNoSeparator); // "T-RexVelociraptorTriceratops"

2. Konwersja string na tablicę: split()

1const dinoString = "T-Rex,Velociraptor,Triceratops";
2
3// Rozdzielenie stringa na tablicę
4const dinosaurs = dinoString.split(",");
5console.log(dinosaurs); // ["T-Rex", "Velociraptor", "Triceratops"]
6
7// Rozdzielenie po każdym znaku
8const letters = "TREX".split("");
9console.log(letters); // ["T", "R", "E", "X"]

Praktyczne przykłady pracy z tablicami

Przykład 1: System inwentaryzacji dinozaurów

1// System inwentaryzacji dinozaurów w Parku Jurajskim
2const dinosaurInventory = {
3  species: [],
4
5  // Dodawanie nowego gatunku do inwentarza
6  addSpecies: function(name, count, carnivore) {
7    // Sprawdzenie czy gatunek już istnieje
8    const existingIndex = this.species.findIndex(s => s.name === name);
9
10    if (existingIndex >= 0) {
11      // Aktualizacja istniejącego gatunku
12      this.species[existingIndex].count += count;
13      console.log(`Zaktualizowano populację ${name}: ${this.species[existingIndex].count}`);
14    } else {
15      // Dodanie nowego gatunku
16      this.species.push({
17        name,
18        count,
19        carnivore,
20        addDate: new Date().toISOString().split('T')[0]
21      });
22      console.log(`Dodano nowy gatunek: ${name} (liczba osobników: ${count})`);
23    }
24
25    return this;
26  },
27
28  // Usuwanie dinozaurów (np. w wyniku śmierci lub transferu)
29  removeSpecimens: function(name, count, reason) {
30    const index = this.species.findIndex(s => s.name === name);
31
32    if (index === -1) {
33      console.log(`Gatunek ${name} nie istnieje w inwentarzu.`);
34      return false;
35    }
36
37    if (this.species[index].count < count) {
38      console.log(`Błąd: Próbujesz usunąć więcej osobników (${count}) niż istnieje (${this.species[index].count}).`);
39      return false;
40    }
41
42    this.species[index].count -= count;
43    console.log(`Usunięto ${count} osobników gatunku ${name}. Powód: ${reason}.`);
44    console.log(`Pozostało: ${this.species[index].count} osobników.`);
45
46    // Jeśli nie ma już żadnych osobników, usuń gatunek z inwentarza
47    if (this.species[index].count === 0) {
48      const removed = this.species.splice(index, 1)[0];
49      console.log(`Gatunek ${removed.name} został całkowicie usunięty z inwentarza.`);
50    }
51
52    return true;
53  },
54
55  // Generowanie podsumowania inwentarza
56  generateSummary: function() {
57    console.log("=== PODSUMOWANIE INWENTARZA DINOZAURÓW ===");
58
59    if (this.species.length === 0) {
60      console.log("Brak dinozaurów w inwentarzu.");
61      return;
62    }
63
64    // Sortowanie gatunków według liczebności (malejąco)
65    const sortedSpecies = [...this.species].sort((a, b) => b.count - a.count);
66
67    // Liczba gatunków i osobników
68    const totalSpecies = sortedSpecies.length;
69    const totalSpecimens = sortedSpecies.reduce((sum, species) => sum + species.count, 0);
70    console.log(`Liczba gatunków: ${totalSpecies}`);
71    console.log(`Łączna liczba osobników: ${totalSpecimens}`);
72
73    // Podział na mięsożerne i roślinożerne
74    const carnivores = sortedSpecies.filter(s => s.carnivore);
75    const herbivores = sortedSpecies.filter(s => !s.carnivore);
76
77    console.log(`Gatunki mięsożerne: ${carnivores.length}`);
78    console.log(`Gatunki roślinożerne: ${herbivores.length}`);
79
80    // Najbardziej liczne gatunki
81    if (sortedSpecies.length > 0) {
82      console.log("\nNajwiększa populacja:");
83      sortedSpecies.slice(0, 3).forEach((species, i) => {
84        console.log(`${i+1}. ${species.name}: ${species.count} osobników`);
85      });
86    }
87
88    // Tabela wszystkich gatunków
89    console.log("\nSzczegółowy wykaz gatunków:");
90    console.log("Nazwa | Liczebność | Typ | Data dodania");
91    console.log("------|------------|-----|-------------");
92    sortedSpecies.forEach(species => {
93      const type = species.carnivore ? "Mięsożerny" : "Roślinożerny";
94      console.log(`${species.name.padEnd(6)} | ${String(species.count).padEnd(10)} | ${type.padEnd(4)} | ${species.addDate}`);
95    });
96  }
97};
98
99// Testowanie systemu inwentaryzacji
100dinosaurInventory.addSpecies("T-Rex", 3, true);
101dinosaurInventory.addSpecies("Velociraptor", 12, true);
102dinosaurInventory.addSpecies("Triceratops", 8, false);
103dinosaurInventory.addSpecies("Brachiosaurus", 5, false);
104dinosaurInventory.addSpecies("Gallimimus", 20, false);
105
106// Aktualizacja istniejących gatunków
107dinosaurInventory.addSpecies("Velociraptor", 4, true); // Dodanie 4 nowych Velociraptorów
108
109// Usuwanie osobników
110dinosaurInventory.removeSpecimens("T-Rex", 1, "Śmierć ze starości");
111dinosaurInventory.removeSpecimens("Gallimimus", 5, "Transfer do innego parku");
112
113// Generowanie podsumowania
114dinosaurInventory.generateSummary();

Przykład 2: Analiza danych genetycznych

1// Przykładowe dane genetyczne (uproszczone) jako tablica
2const geneticData = [
3  { id: "TRX01", species: "Tyrannosaurus", sequenceMatch: 0.85, viability: "High", complete: true },
4  { id: "VLR02", species: "Velociraptor", sequenceMatch: 0.93, viability: "Medium", complete: true },
5  { id: "TRC04", species: "Triceratops", sequenceMatch: 0.79, viability: "Low", complete: false },
6  { id: "BRCH1", species: "Brachiosaurus", sequenceMatch: 0.81, viability: "Medium", complete: true },
7  { id: "STEG7", species: "Stegosaurus", sequenceMatch: 0.76, viability: "Low", complete: false },
8  { id: "ANKL5", species: "Ankylosaurus", sequenceMatch: 0.88, viability: "High", complete: true },
9  { id: "DILO3", species: "Dilophosaurus", sequenceMatch: 0.91, viability: "Medium", complete: false },
10  { id: "PTRD9", species: "Pteranodon", sequenceMatch: 0.72, viability: "Low", complete: false }
11];
12
13// Funkcje analizy danych
14function analyzeGeneticData(data) {
15  console.log("=== ANALIZA DANYCH GENETYCZNYCH ===");
16
17  // 1. Ile sekwencji jest kompletnych?
18  const completeSequences = data.filter(seq => seq.complete);
19  console.log(`Kompletne sekwencje: ${completeSequences.length} z ${data.length} (${((completeSequences.length / data.length) * 100).toFixed(1)}%)`);
20
21  // 2. Średni współczynnik dopasowania sekwencji
22  const averageMatch = data.reduce((sum, seq) => sum + seq.sequenceMatch, 0) / data.length;
23  console.log(`Średnie dopasowanie sekwencji: ${(averageMatch * 100).toFixed(1)}%`);
24
25  // 3. Wyodrębnij najlepsze i najgorsze dopasowania
26  const sortedByMatch = [...data].sort((a, b) => b.sequenceMatch - a.sequenceMatch);
27
28  console.log("\nNajlepsze dopasowania sekwencji:");
29  sortedByMatch.slice(0, 3).forEach((seq, i) => {
30    console.log(`${i+1}. ${seq.species} (ID: ${seq.id}): ${(seq.sequenceMatch * 100).toFixed(1)}%`);
31  });
32
33  console.log("\nNajgorsze dopasowania sekwencji:");
34  sortedByMatch.slice(-3).reverse().forEach((seq, i) => {
35    console.log(`${i+1}. ${seq.species} (ID: ${seq.id}): ${(seq.sequenceMatch * 100).toFixed(1)}%`);
36  });
37
38  // 4. Grupowanie według zdolności do życia (viability)
39  const viabilityGroups = data.reduce((groups, seq) => {
40    if (!groups[seq.viability]) {
41      groups[seq.viability] = [];
42    }
43    groups[seq.viability].push(seq);
44    return groups;
45  }, {});
46
47  console.log("\nGrupowanie według zdolności do życia:");
48  Object.entries(viabilityGroups).forEach(([viability, sequences]) => {
49    console.log(`${viability}: ${sequences.length} sekwencji`);
50    sequences.forEach(seq => {
51      console.log(`  - ${seq.species} (ID: ${seq.id})`);
52    });
53  });
54
55  // 5. Filtry sekwencji priorytetowych do dalszych badań
56  const highPrioritySequences = data.filter(seq =>
57    seq.sequenceMatch > 0.85 && !seq.complete
58  );
59
60  console.log("\nSekwencje priorytetowe do dokończenia:");
61  if (highPrioritySequences.length > 0) {
62    highPrioritySequences.forEach(seq => {
63      console.log(`- ${seq.species} (ID: ${seq.id}): dopasowanie ${(seq.sequenceMatch * 100).toFixed(1)}%, zdolność do życia: ${seq.viability}`);
64    });
65  } else {
66    console.log("Brak sekwencji priorytetowych.");
67  }
68
69  return {
70    totalSequences: data.length,
71    completeSequences: completeSequences.length,
72    averageMatch,
73    bestMatch: sortedByMatch[0],
74    worstMatch: sortedByMatch[sortedByMatch.length - 1],
75    viabilityDistribution: Object.fromEntries(
76      Object.entries(viabilityGroups).map(([key, val]) => [key, val.length])
77    ),
78    highPrioritySequences
79  };
80}
81
82// Wykonanie analizy
83const analysisResults = analyzeGeneticData(geneticData);
84console.log("\nWynik analizy jako obiekt:", analysisResults);
85
86// Filtrowanie i manipulacja danych
87console.log("\n=== MANIPULACJA DANYMI ===");
88
89// 1. Stworzenie nowej tablicy tylko z wybranymi polami
90const simplifiedData = geneticData.map(seq => ({
91  id: seq.id,
92  species: seq.species,
93  match: seq.sequenceMatch
94}));
95console.log("Uproszczone dane:", simplifiedData);
96
97// 2. Filtrowanie do pokazania tylko kompletnych sekwencji z wysokim dopasowaniem
98const highQualitySequences = geneticData.filter(seq =>
99  seq.complete && seq.sequenceMatch > 0.8
100);
101console.log("Sekwencje wysokiej jakości:", highQualitySequences);
102
103// 3. Sortowanie według gatunku alfabetycznie
104const sortedBySpecies = [...geneticData].sort((a, b) =>
105  a.species.localeCompare(b.species)
106);
107console.log("Sortowanie alfabetycznie według gatunku:",
108  sortedBySpecies.map(seq => seq.species)
109);
110
111// 4. Łączenie z inną tablicą (nowe dane)
112const newGeneticData = [
113  { id: "PCHY1", species: "Pachycephalosaurus", sequenceMatch: 0.83, viability: "Medium", complete: true },
114  { id: "SPNO5", species: "Spinosaurus", sequenceMatch: 0.89, viability: "High", complete: false }
115];
116
117const combinedData = [...geneticData, ...newGeneticData];
118console.log(`Połączone dane: ${combinedData.length} sekwencji`);
119
120// 5. Łączenie w string do raportu CSV
121const csvHeader = "ID,Gatunek,Dopasowanie,Żywotność,Kompletne";
122const csvRows = combinedData.map(seq =>
123  `${seq.id},${seq.species},${seq.sequenceMatch},${seq.viability},${seq.complete}`
124);
125const csvReport = [csvHeader, ...csvRows].join('\n');
126console.log("Raport CSV:");
127console.log(csvReport);

Zaawansowane metody tablicowe (ES6+)

Nowoczesny JavaScript dostarcza wielu potężnych metod do pracy z tablicami, które znacznie upraszczają przetwarzanie danych.

1. map() - transformacja elementów

Metoda map() tworzy nową tablicę przez transformację każdego elementu oryginalnej tablicy:

1const dinosaurs = [
2  { name: "Rex", species: "Tyrannosaurus" },
3  { name: "Blue", species: "Velociraptor" },
4  { name: "Spike", species: "Stegosaurus" }
5];
6
7// Pobranie tylko imion
8const names = dinosaurs.map(dino => dino.name);
9console.log(names); // ["Rex", "Blue", "Spike"]
10
11// Tworzenie nowych obiektów
12const dinoLabels = dinosaurs.map(dino => ({
13  label: `${dino.name} (${dino.species})`,
14  id: dino.name.toLowerCase()
15}));
16console.log(dinoLabels);
17// [
18//   { label: "Rex (Tyrannosaurus)", id: "rex" },
19//   { label: "Blue (Velociraptor)", id: "blue" },
20//   { label: "Spike (Stegosaurus)", id: "spike" }
21// ]

2. filter() - filtrowanie elementów

Metoda filter() tworzy nową tablicę zawierającą tylko elementy, które spełniają określone kryterium:

1const dinosaurs = [
2  { name: "Rex", species: "Tyrannosaurus", carnivore: true, weight: 7000 },
3  { name: "Blue", species: "Velociraptor", carnivore: true, weight: 100 },
4  { name: "Spike", species: "Stegosaurus", carnivore: false, weight: 5000 },
5  { name: "Trixie", species: "Triceratops", carnivore: false, weight: 8000 }
6];
7
8// Filtrowanie tylko drapieżników
9const carnivores = dinosaurs.filter(dino => dino.carnivore);
10console.log(carnivores.map(dino => dino.name)); // ["Rex", "Blue"]
11
12// Filtrowanie ciężkich dinozaurów
13const heavyDinos = dinosaurs.filter(dino => dino.weight > 1000);
14console.log(heavyDinos.map(dino => dino.name)); // ["Rex", "Spike", "Trixie"]
15
16// Łączenie warunków
17const heavyCarnivores = dinosaurs.filter(dino => dino.carnivore && dino.weight > 1000);
18console.log(heavyCarnivores.map(dino => dino.name)); // ["Rex"]

3. reduce() - agregacja elementów

Metoda reduce() redukuje tablicę do pojedynczej wartości, przechodząc przez wszystkie elementy:

1const dinosaurs = [
2  { name: "Rex", species: "Tyrannosaurus", weight: 7000 },
3  { name: "Blue", species: "Velociraptor", weight: 100 },
4  { name: "Spike", species: "Stegosaurus", weight: 5000 },
5  { name: "Trixie", species: "Triceratops", weight: 8000 }
6];
7
8// Obliczanie łącznej wagi
9const totalWeight = dinosaurs.reduce((sum, dino) => sum + dino.weight, 0);
10console.log(`Łączna waga dinozaurów: ${totalWeight} kg`); // 20100 kg
11
12// Znajdowanie najcięższego dinozaura
13const heaviestDino = dinosaurs.reduce(
14  (heaviest, dino) => dino.weight > heaviest.weight ? dino : heaviest,
15  dinosaurs[0]
16);
17console.log(`Najcięższy dinozaur: ${heaviestDino.name} (${heaviestDino.weight} kg)`);
18// Najcięższy dinozaur: Trixie (8000 kg)
19
20// Tworzenie obiektu mapującego gatunki na dinozaury
21const dinosBySpecies = dinosaurs.reduce((acc, dino) => {
22  acc[dino.species] = dino;
23  return acc;
24}, {});
25
26console.log(dinosBySpecies.Velociraptor.name); // "Blue"

4. some() i every() - testowanie elementów

Metody te sprawdzają, czy niektóre/wszystkie elementy spełniają określone kryterium:

1const dinosaurs = [
2  { name: "Rex", species: "Tyrannosaurus", dangerous: true, contained: true },
3  { name: "Blue", species: "Velociraptor", dangerous: true, contained: false },
4  { name: "Spike", species: "Stegosaurus", dangerous: false, contained: true }
5];
6
7// Sprawdzenie, czy jakikolwiek dinozaur jest niebezpieczny
8const anyDangerous = dinosaurs.some(dino => dino.dangerous);
9console.log("Czy jakiś dinozaur jest niebezpieczny?", anyDangerous); // true
10
11// Sprawdzenie, czy wszystkie dinozaury są bezpiecznie zamknięte
12const allContained = dinosaurs.every(dino => dino.contained);
13console.log("Czy wszystkie dinozaury są bezpiecznie zamknięte?", allContained); // false
14
15// Sprawdzenie, czy wszystkie niebezpieczne dinozaury są zamknięte
16const allDangerousContained = dinosaurs
17  .filter(dino => dino.dangerous)
18  .every(dino => dino.contained);
19console.log("Czy wszystkie niebezpieczne dinozaury są zamknięte?", allDangerousContained); // false

5. flat() i flatMap() (ES2019)

Metody te spłaszczają zagnieżdżone tablice:

1// Zagnieżdżona tablica dinozaurów według zagród
2const enclosures = [
3  ["Rex", "Rexy"], // Zagroda T-Rexów
4  ["Blue", "Delta", "Echo"], // Zagroda Velociraptorów
5  ["Spike", "Spikey"], // Zagroda Stegozaurów
6  [] // Pusta zagroda
7];
8
9// Spłaszczanie do pojedynczej tablicy
10const allDinos = enclosures.flat();
11console.log(allDinos); // ["Rex", "Rexy", "Blue", "Delta", "Echo", "Spike", "Spikey"]
12
13// Bardziej złożony przykład z flatMap
14const enclosureData = [
15  { type: "T-Rex", dinosaurs: ["Rex", "Rexy"] },
16  { type: "Velociraptor", dinosaurs: ["Blue", "Delta", "Echo"] },
17  { type: "Stegosaurus", dinosaurs: ["Spike", "Spikey"] }
18];
19
20// Mapowanie i spłaszczanie w jednym kroku
21const dinosaursWithTypes = enclosureData.flatMap(enclosure =>
22  enclosure.dinosaurs.map(dino => `${dino} (${enclosure.type})`)
23);
24
25console.log(dinosaursWithTypes);
26// [
27//   "Rex (T-Rex)",
28//   "Rexy (T-Rex)",
29//   "Blue (Velociraptor)",
30//   "Delta (Velociraptor)",
31//   "Echo (Velociraptor)",
32//   "Spike (Stegosaurus)",
33//   "Spikey (Stegosaurus)"
34// ]

Podsumowanie

Tablice są jedną z najpotężniejszych struktur danych w JavaScript, pozwalając na przechowywanie, organizowanie i manipulowanie kolekcjami elementów. W tej lekcji poznaliśmy:

  1. Różne sposoby tworzenia tablic: literały tablicowe, konstruktor Array(), metody Array.of() i Array.from()
  2. Podstawowe operacje na tablicach: dodawanie elementów (push, unshift, splice), usuwanie elementów (pop, shift, splice), dostęp do elementów
  3. Metody wyszukiwania: indexOf, includes, find, findIndex
  4. Metody kopiowania i łączenia: slice, concat, operator spread (...)
  5. Metody sortowania i porównywania: sort, reverse
  6. Metody przekształcania: join (na string), split (ze stringa)
  7. Zaawansowane metody przetwarzania: map, filter, reduce, some, every, flat, flatMap

Umiejętność efektywnego wykorzystania tablic jest niezbędna w codziennej pracy z JavaScript, szczególnie gdy zarządzamy dużymi zbiorami danych, takimi jak nasz wirtualny inwentarz dinozaurów.

W następnej lekcji poznasz metody, które dodają i usuwają elementy tablicy.

Kod do tej lekcji: index.js
1// Tablice - Park Jurajski
2console.log("Laboratorium Tablic JavaScript");
3console.log("Zarządzanie kolekcjami dinozaurów\n");
4
5// ===========================================
6// 1. TWORZENIE TABLIC
7// ===========================================
8console.log("=== 1. Tworzenie tablic ===");
9
10// Sposób 1: Literał tablicowy (najczęstszy)
11const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops"];
12console.log("Literał:", dinosaurs);
13
14// Sposób 2: Konstruktor Array
15const carnivores = new Array("T-Rex", "Velociraptor", "Spinosaurus");
16console.log("Konstruktor:", carnivores);
17
18// Sposób 3: Array.of()
19const herbivores = Array.of("Triceratops", "Stegosaurus", "Brachiosaurus");
20console.log("Array.of():", herbivores);
21
22// Sposób 4: Array.from()
23const dinoNames = "TRex";
24const lettersArray = Array.from(dinoNames);
25console.log("Array.from():", lettersArray);
26
27// Pusta tablica
28const emptyArray = [];
29console.log("Pusta:", emptyArray, "długość:", emptyArray.length);
30
31// Tablica o określonym rozmiarze
32const fixedSize = new Array(5);
33console.log("Rozmiar 5:", fixedSize, "długość:", fixedSize.length);
34
35// ===========================================
36// 2. DOSTĘP DO ELEMENTÓW
37// ===========================================
38console.log("\n=== 2. Dostęp do elementów ===");
39
40const jurassicDinos = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"];
41
42console.log("\nDostęp przez indeks:");
43console.log("Pierwszy [0]:", jurassicDinos[0]);
44console.log("Drugi [1]:", jurassicDinos[1]);
45console.log("Ostatni [-1 = length-1]:", jurassicDinos[jurassicDinos.length - 1]);
46
47// Dostęp do nieistniejącego indeksu
48console.log("Nieistniejący [10]:", jurassicDinos[10]); // undefined
49
50// Długość tablicy
51console.log("\nDługość tablicy:", jurassicDinos.length);
52
53// ===========================================
54// 3. DODAWANIE ELEMENTÓW
55// ===========================================
56console.log("\n=== 3. Dodawanie elementów ===");
57
58const parkDinos = ["T-Rex", "Velociraptor"];
59console.log("\nPoczątkowa lista:", parkDinos);
60
61// push() - dodaj na końcu
62parkDinos.push("Triceratops");
63console.log("push('Triceratops'):", parkDinos);
64
65parkDinos.push("Stegosaurus", "Brachiosaurus");
66console.log("push(2 elementy):", parkDinos);
67
68// unshift() - dodaj na początku
69parkDinos.unshift("Dilophosaurus");
70console.log("unshift('Dilophosaurus'):", parkDinos);
71
72// Bezpośrednie przypisanie do indeksu
73parkDinos[10] = "Pteranodon";
74console.log("parkDinos[10]:", parkDinos);
75console.log("Długość:", parkDinos.length); // 11 (są puste miejsca!)
76
77// ===========================================
78// 4. USUWANIE ELEMENTÓW
79// ===========================================
80console.log("\n=== 4. Usuwanie elementów ===");
81
82const removeDinos = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
83console.log("\nPoczątkowa lista:", removeDinos);
84
85// pop() - usuń ostatni
86const removed1 = removeDinos.pop();
87console.log(`pop(): usunięto '${removed1}'`, removeDinos);
88
89// shift() - usuń pierwszy
90const removed2 = removeDinos.shift();
91console.log(`shift(): usunięto '${removed2}'`, removeDinos);
92
93// delete - tworzy "dziurę" (NIE ZALECANE!)
94delete removeDinos[0];
95console.log("delete removeDinos[0]:", removeDinos);
96console.log("Długość nadal:", removeDinos.length);
97
98// splice() - usuwanie z dowolnego miejsca
99const spliceDinos = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"];
100const removed3 = spliceDinos.splice(2, 1); // Usuń 1 element od indeksu 2
101console.log(`\nsplice(2, 1): usunięto ${removed3}`, spliceDinos);
102
103// ===========================================
104// 5. MODYFIKOWANIE ELEMENTÓW
105// ===========================================
106console.log("\n=== 5. Modyfikowanie elementów ===");
107
108const modifyDinos = ["T-Rex", "Velociraptor", "Triceratops"];
109console.log("\nOryginalna:", modifyDinos);
110
111// Zmiana pojedynczego elementu
112modifyDinos[1] = "Blue (Velociraptor)";
113console.log("Po zmianie [1]:", modifyDinos);
114
115// splice() do zamiany
116modifyDinos.splice(2, 1, "Trike (Triceratops)", "Stego (Stegosaurus)");
117console.log("splice(2, 1, ...2 nowe):", modifyDinos);
118
119// ===========================================
120// 6. KOPIOWANIE TABLIC
121// ===========================================
122console.log("\n=== 6. Kopiowanie tablic ===");
123
124const original = ["T-Rex", "Velociraptor", "Triceratops"];
125
126// Płytka kopia - spread operator
127const copy1 = [...original];
128console.log("\nSpread [...original]:", copy1);
129
130// Płytka kopia - slice()
131const copy2 = original.slice();
132console.log("slice():", copy2);
133
134// Płytka kopia - Array.from()
135const copy3 = Array.from(original);
136console.log("Array.from():", copy3);
137
138// Przypisanie (NIE kopia!)
139const reference = original;
140reference.push("Stegosaurus");
141console.log("\nReferencja (NIE kopia):");
142console.log("original:", original); // Też zmieniony!
143console.log("reference:", reference);
144
145// ===========================================
146// 7. ŁĄCZENIE TABLIC
147// ===========================================
148console.log("\n=== 7. Łączenie tablic ===");
149
150const carnivoreList = ["T-Rex", "Velociraptor", "Spinosaurus"];
151const herbivoreList = ["Triceratops", "Stegosaurus", "Brachiosaurus"];
152
153// concat()
154const allDinos1 = carnivoreList.concat(herbivoreList);
155console.log("\nconcat():", allDinos1);
156
157// Spread operator
158const allDinos2 = [...carnivoreList, ...herbivoreList];
159console.log("Spread:", allDinos2);
160
161// Łączenie z dodatkowymi elementami
162const allDinos3 = [...carnivoreList, "Dilophosaurus", ...herbivoreList];
163console.log("Spread + dodatkowe:", allDinos3);
164
165// ===========================================
166// 8. WYCINANIE I DZIELENIE
167// ===========================================
168console.log("\n=== 8. Wycinanie tablic ===");
169
170const allSpecies = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"];
171
172// slice(start, end) - nie modyfikuje oryginału
173const firstThree = allSpecies.slice(0, 3);
174console.log("\nslice(0, 3):", firstThree);
175console.log("Oryginał:", allSpecies); // Niezmieniony
176
177const lastTwo = allSpecies.slice(-2);
178console.log("slice(-2) - ostatnie 2:", lastTwo);
179
180const middle = allSpecies.slice(1, 4);
181console.log("slice(1, 4) - środek:", middle);
182
183// splice(start, deleteCount, ...items) - modyfikuje oryginał
184const splicedArray = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
185const removedItems = splicedArray.splice(1, 2, "Blue", "Charlie");
186console.log("\nsplice(1, 2, 'Blue', 'Charlie'):");
187console.log("Usunięte:", removedItems);
188console.log("Zmodyfikowana:", splicedArray);
189
190// ===========================================
191// 9. WYSZUKIWANIE W TABLICACH
192// ===========================================
193console.log("\n=== 9. Wyszukiwanie ===");
194
195const searchDinos = ["T-Rex", "Velociraptor", "Triceratops", "Velociraptor", "Stegosaurus"];
196
197// indexOf() - pierwszy indeks
198console.log("\nindexOf('Velociraptor'):", searchDinos.indexOf("Velociraptor"));
199console.log("indexOf('Brachiosaurus'):", searchDinos.indexOf("Brachiosaurus")); // -1 (nie znaleziono)
200
201// lastIndexOf() - ostatni indeks
202console.log("lastIndexOf('Velociraptor'):", searchDinos.lastIndexOf("Velociraptor"));
203
204// includes() - czy zawiera
205console.log("\nincludes('T-Rex'):", searchDinos.includes("T-Rex"));
206console.log("includes('Pteranodon'):", searchDinos.includes("Pteranodon"));
207
208// find() - pierwszy element spełniający warunek
209const longName = searchDinos.find(dino => dino.length > 10);
210console.log("\nfind(dino => dino.length > 10):", longName);
211
212// findIndex() - indeks pierwszego elementu
213const longNameIndex = searchDinos.findIndex(dino => dino.length > 10);
214console.log("findIndex(dino => dino.length > 10):", longNameIndex);
215
216// ===========================================
217// 10. ODWRACANIE I SORTOWANIE
218// ===========================================
219console.log("\n=== 10. Odwracanie i sortowanie ===");
220
221const sortDinos = ["Triceratops", "Velociraptor", "Stegosaurus", "T-Rex", "Brachiosaurus"];
222console.log("\nOryginalna:", sortDinos);
223
224// reverse() - odwraca kolejność (modyfikuje oryginał!)
225const reversed = [...sortDinos].reverse(); // Kopia, żeby nie zmieniać oryginału
226console.log("reverse():", reversed);
227
228// sort() - sortuje alfabetycznie (modyfikuje oryginał!)
229const sorted = [...sortDinos].sort();
230console.log("sort():", sorted);
231
232// Sortowanie niestandardowe
233const weights = [8000, 80, 9000, 50000, 5000];
234console.log("\nWagi:", weights);
235
236const sortedWeights = [...weights].sort((a, b) => a - b);
237console.log("sort() rosnąco:", sortedWeights);
238
239const sortedDesc = [...weights].sort((a, b) => b - a);
240console.log("sort() malejąco:", sortedDesc);
241
242// ===========================================
243// 11. PRZYKŁAD KOMPLEKSOWY
244// ===========================================
245console.log("\n=== 11. System inwentaryzacji - przykład kompleksowy ===");
246
247class DinosaurInventory {
248  constructor() {
249    this.dinosaurs = [];
250  }
251
252  add(name, species, sector, health = 100) {
253    const dino = { id: this.dinosaurs.length + 1, name, species, sector, health };
254    this.dinosaurs.push(dino);
255    console.log(`Dodano: ${name} (${species}) do sektora ${sector}`);
256  }
257
258  remove(name) {
259    const index = this.dinosaurs.findIndex(d => d.name === name);
260    if (index !== -1) {
261      const removed = this.dinosaurs.splice(index, 1)[0];
262      console.log(`Usunięto: ${removed.name}`);
263    } else {
264      console.log(`Nie znaleziono: ${name}`);
265    }
266  }
267
268  findBySector(sector) {
269    return this.dinosaurs.filter(d => d.sector === sector);
270  }
271
272  findBySpecies(species) {
273    return this.dinosaurs.filter(d => d.species === species);
274  }
275
276  getHealthy() {
277    return this.dinosaurs.filter(d => d.health >= 80);
278  }
279
280  getUnhealthy() {
281    return this.dinosaurs.filter(d => d.health < 80);
282  }
283
284  sortByName() {
285    return [...this.dinosaurs].sort((a, b) => a.name.localeCompare(b.name));
286  }
287
288  sortByHealth() {
289    return [...this.dinosaurs].sort((a, b) => b.health - a.health);
290  }
291
292  displayAll() {
293    console.log(`\nINWENTARYZACJA - Łącznie: ${this.dinosaurs.length}`);
294    console.log("=".repeat(60));
295    this.dinosaurs.forEach((dino, i) => {
296      console.log(`${i + 1}. ${dino.name} (${dino.species}) - Sektor ${dino.sector} - Zdrowie: ${dino.health}%`);
297    });
298  }
299
300  displayReport() {
301    console.log("\nRAPORT SZCZEGÓŁOWY");
302    console.log("=".repeat(60));
303
304    const sectors = [...new Set(this.dinosaurs.map(d => d.sector))].sort();
305    sectors.forEach(sector => {
306      const inSector = this.findBySector(sector);
307      console.log(`\nSektor ${sector} (${inSector.length} dinozaurów):`);
308      inSector.forEach(dino => {
309        console.log(`  - ${dino.name} (${dino.species}) - ${dino.health}%`);
310      });
311    });
312
313    const healthy = this.getHealthy();
314    const unhealthy = this.getUnhealthy();
315
316    console.log(`\nZdrowe (${healthy.length}): ${healthy.map(d => d.name).join(", ")}`);
317    if (unhealthy.length > 0) {
318      console.log(`Wymagają uwagi (${unhealthy.length}): ${unhealthy.map(d => d.name).join(", ")}`);
319    }
320  }
321}
322
323// Demonstracja systemu
324const inventory = new DinosaurInventory();
325
326inventory.add("Rexy", "Tyrannosaurus Rex", "A", 95);
327inventory.add("Blue", "Velociraptor", "B", 100);
328inventory.add("Charlie", "Velociraptor", "B", 85);
329inventory.add("Trike", "Triceratops", "C", 70);
330inventory.add("Stego", "Stegosaurus", "C", 92);
331inventory.add("Brachio", "Brachiosaurus", "D", 88);
332
333inventory.displayAll();
334inventory.displayReport();
335
336console.log("\nSortowanie po nazwie:");
337inventory.sortByName().forEach((d, i) => {
338  console.log(`  ${i + 1}. ${d.name}`);
339});
340
341console.log("\nSortowanie po zdrowiu:");
342inventory.sortByHealth().forEach((d, i) => {
343  console.log(`  ${i + 1}. ${d.name} - ${d.health}%`);
344});
345
346inventory.remove("Charlie");
347inventory.displayAll();
348
349console.log("\nGratulacje! Opanowałeś tablice w JavaScript!");

Widzisz błąd w tej lekcji?

Zadania praktyczne w grze

  • Układanie w pionie

    Uporządkuj etapy dodawania nowego gatunku dinozaura do tablicy w JavaScript:

Przydatne artykuły