Predavanje 12: Glava 32 i deo 41

FlipView[{Text[Style[" Branko Urošević, imqfbrankourosevic@gmail.com ",20,"Text",Italic]],Text[Style[" Faculty of Economics, University of Belgrade, NBS and CESIfo Munich",20,"Text", Italic]]}]

Prepoznavanje oblika (Pattern recognition)

Uvod u prepoznavanje oblika

Ideja oblika (patterna) jeste da nađemo fundamentalnu strukturu nekog izraza. Oblici (patterns) su od ogromne važnosti u Wolfram Language. To su objekti koji predstavljaju cele klase izraza istovremeno. Prepoznavanje oblika (pattern matching) je proces pomoću koga se za neki izraz proveri da li odgovara (da li je match-ovan) sa nekim oblikom nekom šablonu ili formi.

Zajedno sa Rule, možete ih koristiti da transformišete bilo koji izraz u oblik koji vas interesuje. Jedna od najvažnijih primena oblika jeste da se upravo pomoću njih definišu korisničke funkcije. Ali, o tome ćemo kasnije. Za sada samo želimo da ukapiramo šta su zapraavo obliki.

Blanko oblik (= bilo šta)

Funkcija MatchQ proverava da li neki izraz ima određeni oblik. Prvi argument jeste izraz koji proveravamo, a drugi argument jeste oblik (pattern) za koji hoćemo da ustanovimo da li matchuje po formi dati izraz. Ukoliko je odgovor potvrdan dobijamo True, a ako match nije ustanovljen dobijamo False.

Oblik _ (čitaj: "blanko") je oblik koji se match-uje sa bilo čim. Pošto blanko oblik pokriva sve moguće izraze koji se mogu napisati u WL, potpuno proizvoljni izrazi će biti matchovan sa _. Na primer, izraz Bob koji nije prethodno definisan je "nešto" pa prema tome biće match-ovan sa blank.

MatchQ[Bob,_]

MatchQ[Log[Bob]+suncica-15,_]

MatchQ["string se matchuje takođe",_]

Dakle, šta god da stavimo bilo šta kao prvi argument u MatchQ, to će biti matchovano oblikom _.

Ograničenje na oblik patterna: _Integer i _Real oblici

Često smo zainteresovani za pattern matching na osnovu tipa (glave) izraza. Na primer, možemo da proverimo da li je nešto Integer (ceo broj). MatchQ uzima objekat (broj 3.15) i pokušava da match njegovu Head (glavu) sa Integer.

MatchQ[#,_Integer]&/@{3.15,"3",21, 3/5}

Ovi odgovori nisu slučajni, pošto su glave ovih izraza sledeće

Head[#]&/@{3.15,"3",21, 3/5}

Uvod u Cases

Funkcija Cases je moćna funkcija koja koristi oblike. Naime, ona izdvaja iz neke liste samo one elemente koji zadovoljavaju određenu formu odnosu matchuju određeni pattern. Pretpostavimo da želimo da iz liste elemenata izdvojimo samo cele brojeve koristeći Cases. Sintaksa je da prvo stavimo listu, a kao drugi argument stavimo odgovarajući oblik (pattern) koji želimo da matchujemo.

Evo primera:

Cases[{21,"27",3+4I,2.15,3/5},_Integer]

Cases je izdvojio samo element 21 pošto je samo taj element matchovan na oblikom _Intereger

MatchQ[#,_Integer]&/@{21,"27",3+4I,2.15,3/5}

Po istom principu, Cases će match-ovati sve elemente ukoliko pattern nema nikakvo ograničenje, to jest ukoliko je samo blank, _

Cases[{21,"27",3+4I,2.15},_]

Prepoznavanje malo apstraktnijeg oblika

Razmotrimo sledeću listu i pronađimo sve izraze koje imaju glavu g:

{g[x],f[x],g[h[x]],Sin[g[x]]}

Pošto Cases matchuje Head nekog izraza možemo da probamo i ovako nešto:

Cases[{g[x],f[x],g[h[x]],Sin[g[x]]},_g]

To možemo proveriti na više načina. Jedan je da vidimo Head svakog od ovih izraza

Head[#]&/@{g[x],f[x],g[h[x]],Sin[g[x]]}

Drugi način bi bio da se za svaki član proveri da li je matchovan sa oblikom _g

MatchQ[#,_g]&/@{g[x],f[x],g[h[x]],Sin[g[x]]}

Primeri: prepoznavanje oblika _Plus, _String i _Times

U prethodnom primeru imali smo apstraknu glavu g koju smo želeli da matchujemo. Naravno, glava može biti bilo koja validna glava. Evo primera. Koji od ovih izraza ima glavu Plus?

Cases[{a+b,2+3,"3+4", a (b+c)},_Plus]

To možemo proveriti i ovako:

Head[#]&/@{a+b,2+3,"3+4", a (b+c)}

Primetimo da u slučaju aritmetričkih operacija na brojevima (kao što je 2+3), WL to odmah izračuna pre nego što Cases stigne da sa tim radi, pa je Head[2+3] =Integer pošto je to u stvari Head[5].

Primetimo da:

Cases[{a+b,2+3,"3+4", a (b+c)},_String]

Cases[{a+b,2+3,"3+4", a (b+c)},_Times]

Prepoznavanje eksplicitnih oblika

Oblici koje smo do sada razmatrali su bile klase izraza (bilo šta, ili samo određeni tip glave). Nekada je korisno matchovati eksplicitne izraze. Pretpostavimo da želimo da obrišemo sve nule u listi brojeva:

{10,-11.1,0,21,0,b}

DeleteCases radi kao Cases samo što briše one elemente koji su matchovani. U ovom slučaju nula je oblik koji treba da se matchuje:

DeleteCases[{10,-11.1,0,21,0,b},0]

To isto možemo da postignemo i korišćenjem Cases, ali je tada argument koji treba da matchujemo sve osim nule, odnosno Except[0]. Drugi rečima ovo ostavlja sve elemente osim nule:

Cases[{10,-11.1,0,21,0,b},Except[0]]

Probajmo da obrišemo sve elemente liste koje su identično jednake celom broju 0.

Cases[{10,-11.1,0.,21,0,b},Except[0]]

Zašto smo je ostao 0. u listi? Razlog je, naravno, da je 0. zapravo realan a ne ceo broj pa nije matchovan.

MatchQ[#,Except[0]]&/@{10,-11.1,0.,21,0,b}

Još primera egzaknog matchovanja

Naravno, ne moramo matchovati samo cele brojeve egzaktno:

Cases[{10,-11.1,0.,21,0,b},b]

Cases[{10,-11.1,0.,21,0,b},Except[b]]

Cases[{10,-11.1,0.,21,0,b},Except[0.]]

Primetimo da smo sada matchovali (i izbacili) iz liste realni broj nula sa tačkom na kraju. Da li je to isto kao i?

Cases[{10,-11.1,0.,21,0,b},Except[0.0]]

Očito, jeste.

Strukturirani oblici: prepoznavanje proizvoljne podliste dimenzije 2

Pretpostavimo da u nekoj složenoj listi želimo da ostavimo samo one podliste koje sadrže tačno dva elementa (bilo koja) ali ne i podliste koje imaju neki drugi broj elemenata. To postižemo oblikom {_,_} ili, u punom obliku, List[_, _]:

Cases[{{1,},{1,},{1,,},{2,,},{2,}},{_,_}]

što je isto što i

Cases[{{1,},{1,},{1,,},{2,,},{2,}},List[_,_]]

Primetimo, naime da lista od tri elementa nema odgovarajući oblik

MatchQ[{1,,},List[_,_]]

dok ga lista od dva elementa ima

MatchQ[{1,},List[_,_]]

Imenovanje oblika

Često je veoma korisno da oblike imenujemo. Umesto da pišemo blanko oblike, možemo oba blanko oblika da zamenimo sa imenovanim blanko oblicima. Ukoliko želimo da matchuje oblike bez ograničenja sa njihove vrednosti onda izrazi koje koristimo za imenovanje moraju da se razlikuju (na primer, p i q). Ovo izdvaja podliste koje imaju tačno dva elementa (proizvoljna):

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},{p_,q_}]

što je isto što i

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},List[p_,q_]]

Primetimo da ime oblika može biti bilo koji validni izraz. Na primer, ovo će raditi potpuno isto:

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},List[tigar_,lav_]]

Pravimo imenovanja

Primetimo da ime kod imenovanog oblika ide pre a ne posle blanka. Naime sova_ je proizvoljni imenovani oblik čije je IME sova dok je _sova oblik koji treba da prepozna one izraze koji imaju glavu sova. Evo primera

Cases[{a,sova[b],sova,c[sova]},sova_]

Primetimo da sova_ matchuje svaki izraz jer je to, zapravo, proizvoljni oblik samo što ima ime sova.  Sa druge strane:

Cases[{a,sova[b],sova,c[sova]},_sova]

matchujemo samo izraze čija je glava sova. Primetimo da

Head[#]&/@{a,sova[b],sova,c[sova]}

Izdvojimo samo one podliste koje imaju dva ista elementa

Evo zašto je korisno imenovati oblike. Oblik liste dimenzije 2 u kojoj su oba elementa ista definišemo pomoću istog imenovanog oblika, recimo {p_,p_}. Evo primer:

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},{p_,p_}]

Primetimo da je to isto što i, na primer

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},{lav_,lav_}]

Izdvojimo podliste sa 3 elementa gde su 2. i 3. element isti

Evo još primera kako rade imenovani patterni. Pretpostavimo da želimo da nađemo sve podliste dimenzije 3 koje imaju poslednja dva elementa jednaka. U tom slučaju to možemo napisati ovako:

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},{lav_,tigar_, tigar_}]

Primetimo da je takvih podlisti samo jedna:

MatchQ[#,List[lav_,tigar_, tigar_]]&/@{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}}

Uslovni (Conditional) pattern matching

Imenovane oblike možemo naterati da zadovoljavaju odrenjene uslove (conditional pattern matching). Ovde ćemo to iskoristiti da po nekim kriterijumima filtriramo podatke. Opšta oznaka za uslovne oblike je expr_/; test. Oblik će biti uspešno prepoznat samo onda kada uslovni test da razultat True.

Iz liste brojeva od 1 do 20 hoćemo da izdvojimo samo one koji su kvadrati celih brojeva. Imenujemo oblik n i zahtevamo da je njegov kvadratni koren ceo broj. U tom slučaju sam broj n je kvadrat celog broja.

Cases[{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},n_/;IntegerQ[(Sqrt[n])]]

Naravno, to isto možemo da uradimo i bez oblika koristeći Select (ova funkcija i Cases mogu da uradi vrlo slične stvari):

Select[{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},IntegerQ[(Sqrt[#])]&]

Generišite listu od 200 nasumice odabranih celih brojeva od 1 do 1000, i iz nje izaberite one deljive sa 7. Iskoristite Module

lista=RandomInteger[{1,1000},200]

Cases[lista,m_/;Mod[m,7]==0]

Odabir elemenata iz proste liste pomoću više od jednog kriterijuma

Pretpostavimo da želimo da iz liste brojeva od 1 do 1000 odaberemo brojeve koji su prosti i koji se završavaju cifrom 3. Kako to možemo da uradimo koristeći Cases i uslovne oblike.

Cases[Range[1000],n_/;PrimeQ[n]&&Last[IntegerDigits[n]]==3]

Prvi uslov određuje da je u pitanju prost broj. Drugi uslov radi ovako. Prvo rastavimo ceo broj na cifre. Nađemo poslednju cifru. Ukoliko je ona jednaka 3 uslov je zadovoljen. Najzad && je logička oznaka za AND, to jest logičko i.

Pronađi proste brojeve od 1 do 1000 koji se završavaju na 7 i koji su veći od 100

Cases[Range[1000],n_/;PrimeQ[n]&&Last[IntegerDigits[n]]==7&&n>100]

Da li ima više prostih brojeva od 1 do 1000 koji se završavaju na 7 ili koji počinju na 7. Prostih brojeva koji se završavaju 7 ima

Cases[Range[1000],n_/;PrimeQ[n]&&Last[IntegerDigits[n]]==7]//Length

Prostih brojeva koji počinju na 7 ima

Cases[Range[1000],n_/;PrimeQ[n]&&First[IntegerDigits[n]]==7]//Length

Primeri sa stringovima

Razmotrimo listu stringova i izdvojimo iz nje one koji imaju bar 6 slova.

Cases[{"stringovi","mama","Ekrem Jevric","farma"},x_String/;StringLength[x]≥ 6]

Iz iste liste stringova izabrati one koji imaju slovo “a” bar 2 puta. Tu je korisna funkcija StringCount.

StringCount["farma","a"]

Cases[{"stringovi","mama","Ekrem Jevric","farma"},x_String/;StringCount[x,"a"]≥ 2]

Naći sve reči u DictionaryLookup[] koje imaju bar 19 karaktera. Koliko ima takvih reči?

Cases[DictionaryLookup[],x_String/;StringLength[x]≥ 19]

Odabir elemenata iz liste parova, to jest iz složenih listi

Iz sledeće liste parova izdvojiti one elemente kod kojih je druga koordinata manje od 6

Cases[{{1,7},{3,4},{4,4},{5,9}},{_,druga_}/;druga<6]

Imenovani oblik je sada {_,druga_} pošto radimo sa parovima (sećate se, nadam se, da ime oblika može biti potpuno proizvoljno). Uslov kaže prosto da je druga koordinata manja od 6. Izabrati elemente čija je prva koordinata manja ili jednaka 4.

Cases[{{1,7},{3,4},{4,4},{5,9}},{prva_,_}/;prva≤ 4]

Generišimo parove brojeva od 1 do 20. Nađite parove čija je suma deljiva sa 6.

Flatten[Table[{i,j},{i,20},{j,20}],1]

Cases[Flatten[Table[{i,j},{i,20},{j,20}],1],{x_,y_}/;Mod[x+y,6]==0]

Za istu listu brojeva naći Pitagorine parove za koje je suma njihovih kvadrata i sama kvadrat nekog celog broja pri čemu drugi broj mora biti veći ili jednak prvom. Evo kako to možemo napisati

pitagoriniBrojevi=Cases[Flatten[Table[{i,j},{i,20},{j,20}],1],{x_,y_}/;IntegerQ[(Sqrt[(x^2)+(y^2)])]&&x≤y]

Oprez kada želimo da matchujemo algebarske izraze

Razmotrimo sledeću stvar. Pokušavamo da matchujemo izraze koji imaju brojilac i imenilac, odnosno oblik Divide[a_,b_] ili a_/b_

Cases[{2,9/3,1/3,(x/(y+z))},((a_)/(b_))]

odnosno

Cases[{2,9/3,1/3,(x/(y+z))},Divide[a_,b_]]

Primetimo da 1/3 nije matchovana sa Divide[a_,b_]

MatchQ[1/3,Divide[a_,b_]]

nego sa Rational[a_,b_]:

MatchQ[1/3,Rational[a_,b_]]

Kombinacija eksplicitnih i opštih oblika

Naći listu koja se sastoji od podlista dužine 2 čiji je prvi element 1. Oblik koji treba da matchujemo možemo napisati na više načina. Jedan je {1, _}. Dakle to je lista od dva elementa u kojoj je prvi element 1.

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},{1,_}]

To isto možemo napisati i pomoću imenovanog oblika ovako

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},List[1,sova_]]

Izdvojimo elemente koji se sastoje od podlisti dužine 2 i čiji je drugi element .

Cases[{{1,},{1,},{,},{,,},{1,},{1,,},{2,,},{2,},{,}},List[djoka_,]]

Alternative i izbacivanje različitih tipova elemenata iz liste

U obliku možemo imati i alternative. Ukoliko nas interesuje izaberemo uređene parove čiji je prvi element ili 1 ili 2 to možemo da uradimo pomoću takozvane operacije alternative. Na primer, 1|2 jeste “ili 1ili 2”.

Cases[{{1,},{1,},{1,,},{2,,},{2,}},{1|2,popadija_}]

Naći elemente dimenzije 2 čiji je drugi element crvena ili plava boja:

Cases[{{1,},{1,},{,1},{1,,},{2,,},{2,}},{dekanat_,|}]

Izbaciti iz liste dole kako 0 tako i 0.0

{10,-11.1,0.,21,0,b}

Cases[{10,-11.1,0.,21,0,b},Except[0.|0]]

ili, koristeći DeleteCases

DeleteCases[{10,-11.1,0.,21,0,b},0.|0]

Kako čistiti listu od nedostajućih podataka u slučaju složenih lista?

Pretpostavimo da želimo da izbacimo sve observacije (redove) koji sadrže element tipa “N-A”, ili “NA”, ili nešto slično u matrici

data={{"NA",0,1},{3,2,1},{4,-1,3},{3,2,"N-A"},{2,"N-A",3}};

Jedan način da se to uradi bi bio nešto ovako

Cases[data,Except[{_String,_,_}|{_,_String,_}|{_,_,_String}]]

Prepoznavanje sekvenci (Sequence matching)

Izraz sa dva blanka __ (“double blank”) matchuje jedan ili više elemenata u nekoj listi. Naravno, njih možemo takođe imenovati. Najbolje je da odmah na primeru vidimo kako to radi.  Kako da nađemo one podliste koje su proizvoljne dužine od najmanje jedan element (za to nam treba dupli blank) a koji se završavaju sa Blue:

Cases[{{1,},{1,},{1,,},{2,,},{2,}},{__,}]

To možemo predstaviti, razume se i nekako ovako:

Cases[{{1,},{1,},{1,,},{2,,},{2,}},List[babaroga__,]]

Vidimo da smo tu dobili sve elemente koji se završavaju sa . Sa druge strane, ukoliko bismo koristili samo jedan blank dobijamo samo one podliste koje se završavaju plavom bojom ali koje imaju dužinu 2:

Cases[{{1,},{1,},{1,,},{2,,},{2,}},{baba_,}]

Kombinacija alternativa i prepoznavanja sekvenci

Naći elemente koji počinju sa 1 ili 2, onda imaju bilo šta i, završavaju se sa  :

Cases[{{1,},{1,},{1,,},{2,,},{2,,,},{2,}},{1|2,__,}]

to je isto što i

Cases[{{1,},{1,},{1,,},{2,,},{2,,,},{2,}},List[1|2,popaj__,]]

Izabrati one podliste koje se završavaju na crvenu  boju, a imaju proizvoljan broj elemenata.

Cases[{{1,},{1,},{1,,},{2,,},{2,,,},{2,}},List[popaj__,]]

Izbrati elemente koji se završavaju sekvencom u kojoj posle crvene ide na kraju plava. Imaju proizvoljan broj elemenata.

Cases[{{1,},{1,},{1,,},{2,,},{2,,,},{2,}},List[popaj__,,]]

Prepoznavanje apstraktnijih izraza pomoguću sekvenci odnosno double blank

Pretpostavimo da želimo da matchujemo bilo koji izraz koji ima Head f i koji ima jedan ili više argumenata. Jedan način da to uradimo jeste da kažemo nešto ovako:

Cases[{f[],g[,],{1,2,3},f[],f[3,4]},f[__]]

To isto možemo da predstavimo, razume se, i pomoću imenovanog oblika

Cases[{f[],g[,],{1,2,3},f[],f[3,4]},f[strudla__]]

Prepostavimo da želimo da matchujemo one izraze u kojima je Head jednak f i gde imamo samo jedan argument.

Cases[{f[],g[,],{1,2,3},f[],f[3,4]},f[_]]

Još o matchovanju listi

Probajmo ovo:

MatchQ[{a,b,c,d},{jedan_}]

Pošto je oblika lista od jednog elementa a mi imamo listu od četiri elementa, ovo daje False. Sa druge strane:

MatchQ[{a,b,c,d},{vise__}]

pošto double blank odgovara bilo kakvoj listi od jednog ili više elemenata. Iz složene liste izdvojimo samo podliste koje imaju dimenziju 1.

Cases[{{a,b,c,d},{1},{2},{3,4}},{_}]

Prepoznavanje algebarskih izraza

Da probamo sada da nađemo koje su variable nešto dignuto na stepen (to se zove monom). Hteli bismo da kao output dobijamo prvi i drugi član. Međutim:

Cases[a (x^3)+b (x^2)+c x+d,(var_)^n_]

Razlog je da su neki od ovih izraza vrlo nested:

FullForm[a (x^3)+b (x^2)+c x+d]

Stoga moramo da sa oblikom idemo duboko unutra. Jedan od načina da to uradimo jeste da idemo beskonačno duboko i tražimo maching:

Cases[a (x^3)+b (x^2)+c x+d,(var_)^n_,Infinity]

Korišćenje prepoznavanja oblika da bismo promenili izraze pomoću Replacement

Jedan od puno načina da se koriste oblici jesu zamene ili replacements. O njima ćemo veoma detaljno pričati u jednoj od narednih glava. Za sada primetimo da je replacement operator  /. (“slash dot”). Veoma je važan u WL.

Zamenite b sa Red u listi:

{a,b,a,a,b,b,a,b}/.b->Red

Zamenite sve podliste od 2 elementa koji počinju sa 1 sa simbolom x. Kako to radi: pattern prvo pronalazi šta treba da se zameni. Onda se sve što treba da se zameni - zameni.

{{1,},{1,},{1,,},{2,,},{2,}}/.{1,_}->x

Lista pravila za zamenu

Možete da imate i listu pravila za zamenu. Ovde imamo listu od dva pravila zamene. Prvo pravilo je da kada imamo podlistu dužine 2 i prvi njen element počinje sa 1 zamenjujemo to podsiltu sa simbolom x. Drugo pravilo kaže da ako imamo podlistu proizvoljne dužine koja se završava sa Blue, zamenjujemo je sa y.

{{1,},{1,},{1,,},{2,,},{2,}}/.{{1,prvo_}->x,{drugo__,Blue}-> y}

Pretpostavimo da želimo da podliste dužine 2 koja ima iste elemente zamenimo sa z. Primetimo da takvih podlista ima dve

Cases[{{1,},{1,},{,},{,},{1,,},{2,,},{2,}},{ista_,ista_}]

a ovako bismo obavili tu zamenu

{{1,},{1,},{,},{,},{1,,},{2,,},{2,}}/.{ista_,ista_}-> z

Složenija upotreba imenovanog oblika

Imenovani patterni su posebno korisni za zamene (replacement). Na primer, nadjemo sve podliste koje imaju dužinu dva i čiji je prvi element 1, pa ih zamenimo na sledeći način:

{{1,},{1,},{1,,},{2,,},{2,}}/.{1,x_}->{x,x,x,Brown}

Naime, umesto te liste dužine dva, imaćemo listu u kojoj će prva tri elementa biti ponovljeni drugi element originalne podliste, a poslednji element će biti Brown. Operacija a->b je isto što i Rule[a,b]. Ako se x_ pojavljuje na levoj strani Rule, onda se na njega može pozivati sa desne strane Rule kao x.

Koristite x sa desne strane Rule da definišemo šta to matchuje  x_:

{f[1],g[2],f[2],f[6],g[3]}/.f[x_]->x+10

Rule može da se koristi i kod Cases. Ovde prvo nalazimo one elemente koje matchuju oblik f[x_], a onda zamenjujemo svuda x sa x+10:

Cases[{f[1],g[2],f[2],f[6],g[3]},f[x_]->x+10]

Jedan od najčešćih primena Rule je da izračunamo vrednost nekog izraza lokalno (u nekoj konkretnoj liniji koda ali ne i globalno)

x^2+y^3/.{x-> 2,y-> 3}

x^2+y^3

Korišćenje oblika i transformacija za preoblikovanje matrica i rad sa podacima

Razmotirmo matricu

data={{9,0,1},{3,2,1},{4,-1,3},{3,2,8},{2,2,3}};

Grid[data]

Koristeći Replacement operator izvući samo prvu kolonu

data/.{prva_,druga_,treca_}->prva

Od originalne matrice naprave drugu u kojoj prva kolona ostaje ista, a suma druge i treće kolone postaje nova druga kolona

data/.{prva_,druga_,treca_}->{prva,druga+treca}

Grid[%]

Q and A

Da li važno kako ćemo nazvati neki pattern (x_ itd)?
Ne. Samo moraju da se konsistentno ta ime koriste. 

Šta još mogu biti patterni?
To ćemo diskutovati kasnije, u poglavlju 41.

Kakva je razlika između | i ||?
p|q je alternativa vezana za pattern, a p||q is a logic construct, that tests whether p or q is True.

Kako se  /. interpretira?
To je funkcija ReplaceAll. Replace pokušava da zameni odgovarajuče patterne u celom izrazu. ReplaceList daje listu rezultata svih mogućih načina da se matchuje neki pattern. 

Ako /. ima više replacementa, koji će koristiti?
Koristi prvu na koju naiđe. Ako replacements mogu da se naprave na raznim nivoima izraza, /. pravi zamenu na najmanjem nivou (koji je najviše spolja).

Tehnički komentari
Patterns za stringove ćemo diskutovati u odeljku 42.

Pattern matching u Wolfram Language uzima u obzir ekvivalenciju izraza kao što x+y i y+x, ili x+(y+z) i (x+y)+z.

Kada pišemo lhs->rhs, lhs je “left-hand side” a rhs je “right-hand side”.