nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Učionica
  • Saveti
  • Zanimljivosti
  • Kontakt

Operacije sa nizovima u programskom jeziku JavaScript

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark

Uvod

Nizovi u JavaScript-u, deklarišu se i inicijalizuju na vrlo komotan način, ne podležu strogoj tipizaciji (niz može sadržati elemente različitog tipa), interna implementacija nizova je prilično kompleksna, a ako bismo baš hteli - našli bismo bar još koju 'zamerku'. :)

Međutim, mora se priznati da, u radu sa nizovima u JS-u, ima šarma i lepote (ima i svega navedenog iz prethodne rečenice; nismo zaboravili), i mora se priznati da u većini situacija u praksi - naravno, pod uslovom da "pazimo šta radimo" - stvari funkcionišu prilično glatko.

Pristup koji predlažemo čitaocima (i koji primenjujemo u praksi), podrazumeva da - kada već programski jezik dozvoljava "sve i svašta" - vođenje računa o bitnim stvarima preuzmemo na sebe i sa nizovima postupamo onako kako bismo postupali da koristimo jezik sa strogom tipizacijom.

U takvim okolnostima, JavaScript nam neće priređivati neprijatna iznenađenja.

Nizovi u JavaScript-u uopšteno

Za početak, valja razmotriti šta se (uopšte), u JavaScript-u podrazumeva pod pojmom "niz", jer krajnji rezultat zavisi od endžina koji se koristi, * pa ne možemo biti sigurni šta se dešava "ispod haube", gde "niz" može biti zapisan: bilo kao statički niz, bilo kao hash-mapa, sve u zavisnosti od okolnosti.

* JavaScript endžin je program koji se koristi za interpretaciju JS koda unutar drugog programa, tipično, unutar browsera (najpoznatiji JS endžini su V8, koji koriste Google Chrome i Node JS, i SeaMonkey, koji koristi Mozilla Firefox).

Ovoga puta, bićemo praktični i nećemo ulaziti u detaljnu diskusiju o implementaciji nizova (ostavićemo to za neku drugu priliku), ali ćemo za sada definisati nizove u JavaScript-u kao posebne promenljive koje omogućavaju smeštanje kolekcija podataka preko jednog identifikatora (naziva promenljive), pri čemu podaci ne moraju biti istog tipa, a moguće je i proizvoljno dodavanje i uklanjanje elemenata.

Deklaracija

Osnovni vid deklaracije niza u JS-u (praktično) podrazumeva i inicijalizaciju praznog niza u istoj liniji koda (jer, ukoliko izostavimo inicijalizaciju, promenljiva neće biti referenca na (prazan) niz, već objekat sa sistemskom vrednošću null):

		
let niz = [ ];
		
	
Slika 1. - Deklaracija niza u JavaScript-u.

Niz je prazan, ali, svakako mu se u daljem toku izvršavanja programa, mogu dodavati elementi.

Inicijalizacija

Pored inicijalizacije praznog niza (kakvu smo već videli), često * se javlja i inicijalizacija/deklaracija koja podrazumeva zadavanje (nekoliko) elemenata:

		
let niz   = [ 1, 2, 2, 3, 4, 5, 5 ];
let imena = [ "Milan", "Petar", "Jovan" ];
		
	
Slika 2. - Inicijalizacija niza u JavaScript-u.

* Rekli bismo da kod sa slike #2 predstavlja najtipičniji primer (promenljiva se deklariše kao niz, koji se popunjava elementima).

Takođe, niz može biti inicijalizovan i preko funkcija koje vraćaju nizove.

		
let niz = funkcijaKojaVracaNiz(ulaz);

// Primer:

let s     = "papir;kamen;makaze";
let lista = s.split(";"); // [ "papir" , "kamen" , "makaze" ]
		
	
Slika 3. - Inicijalizacija niza u JavaScript-u - preko funkcije koja vraća niz.

Što se tiče inicijalizacija koje smo videli na slici #3, na scenu stupa "preuzimanje odgovornosti" sa naše strane.

Ako za inicijalizaciju koristimo funkciju koju smo sami definisali, postaraćemo se da funkcija: ili uredno inicijalizuje niz, ili da vrati izlaznu vrednost po kojoj ćemo prepoznati da je došlo do greške (ne moramo obavezno koristiti izuzetke i blok try-catch, ali svakako nećemo prihvatati "zdravo za gotovo" da je niz uredno inicijalizovan).

Ukoliko koristimo gotova rešenja, konsultovaćemo dokumentaciju i ponovo biti pažljivi.

.... a sa funkcijom split ćemo se detaljnije upoznati u nastavku.

Pristup elementima

Pristup elementima niza, obavlja se na način koji je uobičajen u programskom jeziku C, * uz navođenje indeksa u velikoj zagradi.

		
let imenaNiz = [ "Dejan" , "Milan" , "Jovan" ];
let imeOsobe = imenaNiz[2]; // "Jovan"
		
	
Slika 4. - Pristup elementu niza u JavaScript-u.

* Navedeni pristup, može se smatrati donekle "čudnim", budući da "niz" u JavaScript-u "najverovatnije" nije implementiran kao statički niz, ali, bićemo praktični: iako znamo da nisu u pitanju statički nizovi - nećemo se previše brinuti oko svih navedenih pojedinosti.

Kao i u C-u, indeksiranje počinje od nule (pa je u nizu od 5 elemenata, poslednji indeks koji možemo koristiti 4).

Očitavanje dužine niza (length)

Dužinu niza (broj elemenata), možemo očitati preko svojstva length:

		
let d = niz.length;
		
	
Slika 5. - Određivanje dužine niza u JavaScript-u.

Sada možemo (recimo), napraviti i for petlju koja će pristupiti svim elementima:

		
for (let i = 0; i < d; ++i) {
	niz[i] = niz[i] + 1;
}
		
	
Slika 6. - For petlja u kojoj se koristi prethodno ustanovljena dužina niza.

Kao i mnogi drugi jezici, JavaScript takođe raspolaže i "specijalizovanom for petljom" koja je specifično namenjena prolasku kroz ceo niz (u pitanju je konstrukcija forEach, kojoj ćemo više pažnje posvetiti pred kraj).

Dodavanje elementa na kraj niza (push)

Za dodavanje elementa na kraj niza, koristi se komanda push:

		
// [ 1, 2, 2, 3, 4, 5, 5 ]
niz.push(10); // [ 1, 2, 2, 3, 4, 5, 5, 10 ]
		
	
Slika 7. - Funkcija push - dodavanje elementa na kraj niza.

Za dodavanje elementa (ili elemenata) na proizvoljnu poziciju, koristi se funkcija splice (više o funkciji splice u nastavku).

Uklanjanje elemenata sa početka ili kraja niza (pop i shift)

Kada je u pitanju uklanjanje elemenata, razlikujemo tri slučaja:

  • uklanjanje elementa sa kraja niza
  • uklanjanje elementa sa početka niza
  • uklanjanje elementa sa proizvoljne pozicije

Element sa kraja niza, uklanja se preko komande pop:

		
// niz: [ 1, 2, 2, 3, 4, 5, 5, 10 ]
let p = niz.pop();

// p:   10
// niz: [ 1, 2, 2, 3, 4, 5, 5 ]
		
	
Slika 8. - Funkcija pop - Uklanjanje elementa sa kraja niza.

Element sa početka niza, uklanja se preko komande shift:

		
// niz: [ 1, 2, 2, 3, 4, 5, 5 ]
let p = niz.shift();

// p:   1
// niz: [ 2, 2, 3, 4, 5, 5 ]
		
	
Slika 9. - Funkcija shift - Uklanjanje elementa sa početka niza.

Može se reći da, u idejnom smislu, funkcija shift nalikuje bitovskom operatoru <<.

Kada je u pitanju uklanjanje elementa sa proizvoljne pozicije, koristi se (već pomenuta) funkcija splice, s tim da je u pitanju univerzalna komanda preko koje je moguće obaviti: i dodavanje, i uklanjanje.

Funkcija splice - dodavanje i/ili uklanjanje elemenata na proizvoljnoj poziciji

Poslednje što smo naveli u prethodnom odeljku, može delovati pomalo čudno, ali, komanda splice je veoma univerzalna i može se koristiti za obe operacije:

		
niz.splice(indeks, n_uklanjanje, elementi_za_dodavanje ....);

// indeks       - indeks na kome se obavlja dodavanje, ili
//                od koga počinje uklanjanje
// n_uklanjanje - broj elemenata koje treba ukloniti
// elementi     - lista elemenata koji će biti dodati
		
	
Slika 10. - Funkcija splice - Univerzalna funkcija za uklanjanje i dodavanje elemenata.

Kao što vidimo, zaista veoma univerzalno, ali - kako to (sve) funkcioniše u praksi?!

Usput: reč u nazivu funkcije - "splice" (koja može zvučati pomalo čudno), u prevodi označava "uplitanje" (konopaca, žica i sl).

Dodavanje elemenata

Za dodavanje elemenata, potrebno je postaviti indeks na poziciju koja odgovara mestu na kome želimo da se pojavi prvi element iz liste novih elemenata i takođe, potrebno je naglasiti da se nijedan element ne uklanja (drugi argument je 0).

Od trećeg argumenta počinje lista elemenata koji se umeću.

Ako je i indeks za umetanje, a n broj elemenata za umetanje, cela operacija podrazumeva umetanje liste od n elemenata između pozicija i i i + 1.

		
let niz = [ 1 , 2 , 3 , 4 , 5 ]

niz.splice(2, 0, 1001, 1002)
// [ 1 , 2 , 1001 , 1002 , 3 , 4 , 5 ] 
		
	
Slika 11. - Primer dodavanja elemenata preko funkcije splice.

U konkretnom primeru, između druge i treće pozicije, umeću se dva nova elementa (1001, 1002).

Uklanjanje elemenata

Za uklanjanje elemenata, potrebno je navesti dva parametra: indeks prvog elementa koji se uklanja i ukupan broj elemenata koje je potrebno ukloniti.

		
let niz = [ 1 , 2 , 3 , 4 , 5 ]

niz.splice(2, 1)
// [ 1 , 2 , 4 , 5 ] 
		
	
Slika 12. - Primer uklanjanja elemenata preko funkcije splice.

U konkretnom primeru, na trećoj poziciji (indeks 2), uklonili smo jedan element.

Ako funkciji predamo (samo) dva argumenta, jasno je da nema dodavanja.

Kombinovani pristup

Po potrebi, prethodne dve operacije je moguće kombinovati (pri čemu se obavezno predaje tri ili više argumenata).

Prvo se uklanja određen broj elemenata (onoliko koliko je navedeno preko drugog argumenta) - počevši od indeksa koji je naveden kao prvi argument - pa se zatim umeću novi elementi, na mesto koje (praktično) odgovara poziciji na kojoj je došlo do uklanjanja.

		
let niz = [ 1 , 2 , 3 , 4 , 5 ]

niz.splice(2, 2, 2001, 2002)
// [ 1 , 2 , 2001, 2002, 5 ] 
		
	
Slika 13. - Primer kombinovanog uklanjanja i dodavanja preko funkcije splice.

U konkretnom primeru, prvo se uklanjaju elementi sa indeksima 2 i 3 (dva elementa, počevši od indeksa 2), a zatim se između novih indeksa 1 i 2 (ili uslovno rečeno, između prvobitnih indeksa 1 i 4), umeću novi elementi (2001 i 2002).

Spajanje nizova (concat)

U JavaScript-u, dva niza možemo spojiti preko funkcije concat, na sledeći način:

		
let a = [ 1, 2, 3 ];
let b = [ 4, 5, 6 ];
let c = a.concat(b); // [ 1, 2, 3, 4, 5, 6 ]
		
	
Slika 14. - Funkcija concat - Spajanje nizova.

"Concat" je skraćenica od "concatenate" (ili "concatenation"), a konkatenacija je (u praksi malo previše "zvaničan"), termin koji označava spajanje niski znakova (ali se u većem broju programskih jezika, kao što vidimo, vezuje i za operaciju spajanja nizova opšteg tipa).

Sortiranje nizova (sort)

Možemo naravno implementirati i sopstvene funkcije za sortiranje nizova, ali, možemo umesto toga jednostavno pozvati sledeći kod ....

		
let a = [ 2, 1, 3, 5, 4 ];
a.sort(); // [ 1, 2, 3, 4, 5 ]
		
	
Slika 15. - Funkcija sort - Uređivanje niza u neopadajući poredak.

.... i niz će biti sortiran.

U praksi (pogotovo za jednostavne primere), više nego prihvatljivo.

Baš kao što i sama implementacija nizova zavisi od konkretnog JS endžina, tako i izbor konkretnog algoritma za sortiranje, zavisi od sadržaja niza (nećemo previše ulaziti u detalje, ali, najčešće je u pitanju algoritam Quick Sort, sa složenošću O(nlogn)).

Spajanje niza u nisku znakova (join)

Ukoliko želimo da niz elemenata spojimo u nisku, možemo koristiti komandu join:

		
let a  = [ "N", "i", "z", "o", "v", "i" ];
let s1 = a.join();    // "N,i,z,o,v,i"
let s2 = a.join("*"); // "N*i*z*o*v*i"
let s2 = a.join("");  // "Nizovi"
		
	
Slika 16. - Funkcija join - Spajanje elemenata niza u nisku znakova.

Ukoliko se funkciji join ne preda argument, rezultujuća niska nastaje direktnim spajanjem elemenata niza, uz dodavanje zareza između svaka dva susedna elementa.

Ukoliko se, kao argument, preda niska (koja predstavlja crtu, prelazak u novi red i sl), predata niska se (u okviru rezultujuće niske), pojavljuje između svaka dva elementa prvobitnog niza (videti gornji primer).

U obradi tekstualnih datoteka, komanda join (baš kao i komanda split, koju ćemo prikazati u narednom odeljku), koristi se često.

Pretvaranje niske znakova u niz (split)

Deljenje niske obavlja se preko funkcije split, rezultat je lista elemenata, a kao kriterijum za podelu, može se koristiti određena niska ili regularni izraz:

		
let s = "Pariz-London-Lisabon";
let a = s.split("-"); // [ "Pariz", "London", "Lisabon" ]
		
	
Slika 17. - Funkcija split - Kreiranje niza podelom niske znakova.

Kao što je pomenuto, funkcije join i split jako dobro dođu u obradi teksta, pa tako (na primer), možemo pravilno formatirati listu imena u kojoj se separatori (znakovi za razdvajanje), ne koriste na dosledan način:

		
// Dobre informacije, ali, nedosledna
// upotreba znakova za razdvajanje:
let s = "Milan Ivan, Jovan # Dejan";

// Regex je praktično kolekcija svih "razdvajača":
let regex = /([ ,#])/

let lista = s.split(regex); // [ "Milan", " " , "Ivan", ",",
                            //   " ", "Jovan", " ", "#",
                            //   " " , "Dejan" ]

// Napomena: u praksi, lista bi sadržala i nekoliko
// praznih stringova ("")

let nova_lista = [];

for (let i = 0; i < lista.length; ++i) {
	// Ako je element liste prazna niska ili neki
	// od separatora, nećemo takav element ubacivati
	// u novu listu:
	if (lista[i] == "" || lista[i].match(regex)) {
		continue;
	}
	
	// Sve ostale elemente (praktično - samo imena),
	// ubacićemo u novu listu:
	nova_lista.push(lista[i]);
}

// Na kraju, spojićemo listu u ("običnu") nisku,
// u kojoj će svako ime biti zapisano u novom redu

let s2 = nova_lista.join("\n");
		
	
Slika 18. - Praktičan primer korišćenja funkcija split i join.

Nisku smo rastavili preko funkcije split, prošli smo kroz sve elemente liste (koja je nastala rastavljanjem niske), izdvojili smo imena i na kraju smo od liste formirali ("običnu") nisku, preko funkcije join.

Funkcije višeg reda za rad sa nizovima

Funkcije koje smo nabrojali u članku nisu naravno (ni iz daleka), sve funkcije koje se u JS-u koriste za rad sa nizovima, već samo one koje smatramo najkorisnijim za sam početak.

Iako smo članak namenili korisnicima sa ne-baš-mnogo iskustva, osvrnućemo se i na nekoliko (ponešto) naprednijih funkcija za rad sa nizovima, koje se obično koriste u sprezi sa tzv. "lambda" notacijom.

Ne dajte da vas navedeni termini zaplaše, jer, u pitanju je prilično jednostavan način zapisa koji većina programera (čak i mlađih i/ili neiskusnijih), može lako prihvatiti intuitivno, a kada bude došlo vreme, možete se detaljno upoznati sa sintaksom funkcija povratnih poziva i lambda izraza.

every

Sledeći kod ....

		
a.every(x => x > 1)
		
	
Slika 19. - Funkcija every, koja proverava da li svaki element niza zadovoljava određeni kriterijum.

.... vraća vrednost true pod uslovom da su svi elementi niza veći od 1 (u suprotnom, povratna vrednost je false).

some

Sledeći kod ....

		
a.some(x => x > 10)
		
	
Slika 20. - Funkcija some, koja proverava da li bar jedan element niza zadovoljava određeni kriterijum.

.... vraća vrednost true pod uslovom da je bar jedan element niza veći od 10 (u suprotnom, povratna vrednost je false).

map

Ukoliko želimo da kopiramo niz, i pri tom novim elementima dodelimo određene vrednosti preko funkcije, možemo koristiti sledeću sintaksu:

		
let a = [ 1, 2, 3, 4, 5 ];
let b = a.map(x => x * x);
		
	
Slika 21. - Funkcija map, koja kreira kopiju niza prema pravilu koje je određeno unutrašnjom funkcijom.

Pokretanjem poslednje skripte, nastaće novi niz sa vrednostima [ 1, 4, 9, 16, 25 ] (koje predstavljaju kvadrate vrednosti iz ulaznog niza).

filter

Ukoliko je potrebno da - pri kopiranju niza - uklonimo određene vrednosti, možemo koristiti komandu filter.

Cela operacije podrazumeva kreiranje novog niza, u koji će biti kopirane samo vrednosti koje zadovoljavaju uslov:

		
let a = [ 1, 2, 3, 4, 5 ];
let b = a.filter(x => x > 3);
		
	
Slika 22. - Funkcija filter, koja u novi niz kopira samo određene elemente, shodno uslovu.

U primeru sa gornje slike, novi niz sadržaće samo elemente 4 i 5.

forEach

Za pojednostavljeni zapis petlje koja prolazi kroz ceo niz, možemo (kao što smo već nagovestili), koristiti sledeću sintaksu:

		
let a = [ 1, 2, 3, 4, 5 ];

a.forEach(element => {
	console.log(element);
});
		
	
Slika 23. - Funkcija forEach, koja obilazi sve elemente niza.

Primećujemo da pri korišćenju funkcije forEach, elementima ne pristupamo preko indeksa, već preko reference element (s tim da je u pitanju proizvoljno izabran identifikator).

Sintaksa deluje intuitivno, međutim, forEach nije petlja, nego (lambda) funkcija, pa se tako (na primer), za prekid ciklusa ne koristi rezervisana reč break, već return.

Kod koji smo prikazali jeste intuitivan, ali, da biste za prave razumeli sve što smo naveli o funkcijama kao što su map, filter i sl, biće neophodno da se (u dogledno vreme), detaljnije upoznate sa funkcijama povratnog poziva i lambda izrazima (za šta možete iskoristiti članak koji smo već ranije linkovali).

Za kraj ....

Kao što smo videli, rad sa nizovima u JS-u nije nikakav "bauk" (naravno, uz opasku da svakako moramo voditi više računa nego u strogo tipiziranim jezicima, gde ipak postoje određeni mehanizmi koji će nas sprečiti da u niz celobrojnih vrednosti dodajemo niske i slično).

Sledeći članak o JS-u posvetićemo implementaciji čvorova i struktura podataka ....

Autor članka Nikola Vukićević Za web portal www.codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu www.codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta www.codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2023. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna Početna > Članci > Operacije sa nizovima u programskom jeziku JavaScript

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 25.12.2020.

trejler_olovka Poslednja izmena: 16.04.2021.

trejler_dokument Jezici: JavaScript

trejler_teg_narandzasti Težina: 6/10

Povezani članci

Povezani članci

Svi članci
Code never lies; comments sometimes do.
Ron Jeffries
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu www.codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta www.codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2023. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt