Ի՞նչպես կատարել զանգվածի տեսակավորում՝ (sorting) օգտագործելով ներդրված sort մեթոդը։ Ի՞նչու երբ տեսակավորում ենք թվերի զանգված, արդյունքը կարող է մեզ անակնկալի բերել, և ի՞նչպես կարող ենք որպես արգումենտ փոխանցվող ֆունկցիայի օգնությամբ ստանալ ճիշտ տեսակավորված թվերի զանգված։ Ի՞նչպես ստանալ էլեմենտների պատահական դասավորվածությամբ զանգված։
JavaScript-ում զանգվածների տեսակավորումը կատարվում է array.sort
մեթոդի օգնությամբ։ Այս մեթոդի աշխատանքի սկզբունքները շատերը հաճախ չեն պատկերացնում այնպես, ինչպես հարկն է։ Մեթոդի ներքին իրականացումը հիմնականում արագ տեսակավորման ալգորիթմի օգնությամբ է (QuickSort Algorithm), իսկ սկզբնապես տեսակավորումը կատարվում է ըստ լեքսիկոգրաֆիկ (բառարանագրային) հերթականության։ Պարզ ասած՝ ըստ այբենական հերթականության, միայն այն տարբերությամբ, որ ցանկացած մեծատառ փոքր է նույն այբուբենին պատկանող ցանկացած փոքրատառից։
Պետք է նշել, որ sort
մեթոդը ՓՈԽՈՒՄ է զանգվածը, որի վրա կանչվել է, և նոր վերադարձնում է տեսակավորված զանգված։ Սա մեթոդի կարևոր առանձնահատկություն է, որն անհրաժեշտ է հիշել։ Կատարել զանգվածի տեսակավորում՝ շատ հեշտ է, ուղղակի զանգվածի վրա կանչում ենք մեթոդը՝ առանց լրացուցիչ պարամետրերի։ Իսկ թե ե՞րբ է անհաժեշտ մեթոդին արգումենտ տալ, դեռևս կանդրադառնամ:
Բերեմ պարզ օրինակ՝
let arr = ["Hasmik", "Armen", "Nelly"];
arr.sort();
console.log(arr); // ["Armen", "Hasmik", "Nelly"]
Մենք զանգվածը տեսակավորեցինք ըստ աճման կարգի, "H" տառը հաջորդում է "A" տառին, իսկ "N"-ը "H"-ին։ Եթե մեզ պետք է տեսակավորել ըստ նվազման կարգի, այդ դեպքում անհրաժեշտ կլինի sort
մեթոդից հետո անմիջապես օգտագործել նաև reverse
մեթոդը․
arr.sort().reverse();
console.log(arr); // ["Nelly", "Hasmik", "Armen"]
Իսկ հիմա եթե մեթոդն օգտագործենք թվերի զանգվածի վրա, մենք կստանանք ոչ այն, ինչ հավանաբար ուզում էինք
let numArray = [7, 50, 300];
numArray.sort();
console.log(numArray); // [300, 50, 7] Oops!
Մեթոդը թվերի տեսակավորումը փաստացի կատարում է այնպես, ինչպես տողերինը։ Սկզբից համեմատում է առաջին սիմվոլները, եթե առաջին թվի առաջին սիմվոլը փոքր է երկրորդ թվի առաջին սիմվոլից, ապա համարում է որ առաջին թիվը փոքր է երկրորդ թվից և համեմատությունն այլևս չի շարունակում։ Մեր օրինակում երբ համեմատում է 7-ն ու 50-ը, սկզբից վերցնում է նախ առաջին սիմվոլները, "7" > "5", այլևս չի շարունակում համեմատել, և համարում է որ 7-ը 50-ից մեծ է, ու ըստ այդմ էլ տեսակավորում է:
Դիմենք մեր սիրելի MDN-ի օգնությանը, որպեսզի հասկանանք թե ինչ կարելի է անել այս իրավիճակում: Նախ այնտեղ կարդում ենք, որ տեսակավորումը default կատարվում է ըստ Unicode-ում տվյալ սիմվոլի կոդի համարների հերթականության։ Հետո նկատում ենք, որ մեթոդի գրելաձևը ենթադրում է նաև ոչ պարտադիր պարամետրի առկայություն։
arr.sort([compareFunction])
compareFunction
- Ոչ պարտադիր պարամետր է։ Իրենից ներկայացնում է հետադարձ կանչի ֆունկցիա, որը սահմանում է թե ինչ օրինաչափությամբ պետք է կատարվի զանգվածի տեսակավորումը։ Եթե բացակայում է, ապա զանգվածի էլեմենտը անուղղակիորեն վերափոխվում է String տիպի, և տեսակավորումը կատարվում է ըստ Unicode-ում տվյալ սիմվոլի դիրքի։
Որպեսզի թվային զանգվածում կատարենք ճիշտ տեսակավորում՝ մեզ անհրաժեշտ է մեթոդին որպես արգումենտ տալ հետևյալ հետադարձ կանչի ֆունկցիան՝
function(a, b) {return a - b}
Այս ֆունկցիան հաղորդելով որպես արգումենտ՝ մենք հնարավորություն ենք տալիս sort
մեթոդին 2 էլեմենտների պարզագույն համեմատություն անել և գտնել թե որն է որից մեծ։ Եթե հետադարձ կանչի ֆունկցիայի վերադարձրած արժեքը լինում է բացասական, ապա մեթոդը հասկանում է, որ երկրորդ թիվը մեծ է առաջինից, հերթականությունը ճիշտ է, և ոչ մի բան անելու հարկ չկա։ Երբ հետադարձ կանչի ֆունկցիան վերադարձնում է 0, ապա մեթոդը հասկանում է, որ թվերը հավասար են իրար, և կրկին ոչ մի բան պետք չի անել։ Իսկ այ երբ հետադարձ կանչի ֆունկցիան վերադարձնում է դրական թիվ՝ դա բնականաբար հնարավոր է միայն այն դեպքում, երբ առաջին թիվը մեծ է երկրորդ թվից, հետևաբար հերթականությունը ճիշտ չէ, և մեթոդը տեղերով փոխում է թվերին։
Հիմա փորձենք մեր վերևի օրինակի զանգվածի վրա կանչել sort
մեթոդը՝ որպես արգումենտ նրան տալով վերը նկարագրված հետադարձ կանչի ֆունկցիան։
numArray.sort(function (a, b) {
return a - b;
});
Կստանանք [7, 40, 300], ինչը և ուզում էինք։
Եվս մի նկատառում՝ երբեմն մեզ անհրաժեշտ է ստանալ տեսակավորված զանգված, սակայն ոչ թե աճման՝ այլ նվազման կարգով։ Ի՞նչպես անել։ Դա շատ հեշտ է, ընդամենը պետք է որպես արգումենտ հաղորդվող հետադարձ կապի ֆունկցիայի մարմնում վերադարձնել ոչ թե a - b
, այլ b - a
: Փորձենք․
numArray.sort(function (a, b) {
return b - a;
});
Կստանանք [300, 40, 7], այն ինչ ակնկալում էինք։
Կոդը կարելի է դարձնել ավելի կարճ և գեղեցիկ, եթե հետադարձ կապի ֆունկցիան գրենք՝ օգտագործելով ES6-ի arrow function նոտացիան։ Օրինակ աճման կարգով տեսակավորելու դեպքում ՝
numAarray.sort((a, b) => a - b);
Նվազման կարգով տեսակավորելու դեպքում՝
numArray.sort((a, b) => b - a);
Եվ ամենավերջում ներկայացնեմ մի քանի հետաքրքիր եղանակ, թե ինչպես տեսակավորել թվերի զանգվածը՝ ստանալով էլեմենտների լրիվ պատահական հերթականություն։ Դրա համար կարող ենք որպես արգումենտsort
մեթոդին հաղորդել հետևյալ ֆունկցիաները՝
const shuffle = (a, b) => 0.5 - Math.random();
myArray.sort(shuffle);
const shuffle2 = (a, b) => Math.random() - Math.random();
myArray.sort(shuffle2);
const shuffle3 = (a, b) => a * Math.random() - b * Math.random();
myArray.sort(shuffle3);
Ամեն կանչի արդյունքում կստանանք տարբեր արդյունքներ, և այս եղանակը երբեմն կիրառվում է որոշ խնդիրների լուծման համար։