Thao Tác Với Mảng 2 Chiều Trong Javascript Thế Nào?

Thao Tác Với Mảng 2 Chiều Trong Javascript Thế Nào?

Về mặt bản chất, mảng 2 chiều (2D Array) là khái niệm về chuỗi các ma trận – matrix, được sử dụng để chứa thông tin. Mỗi 1 thành phần lại có chứa 2 chỉ số riêng biệt: row (y) – dòng và column (x) – cột. Ma trận sẽ tiến hành xử lý mỗi khi bạn nhập vào dòng và cột dữ liệu.

Mảng 1 chiều và mảng 2 chiều khác nhau thế nào?

Ví dụ: Trước hết, mình cho các bạn xem lại hình ảnh minh họa cho mảng một chiều trên máy tính:

Đây là mảng 1 chiều gồm có 5 phần tử được đánh chỉ số từ 0 đến 4.

Và dưới đây là hình ảnh minh họa cho cách tổ chức dữ liệu mảng hai chiều:

Đây là bảng câu đố của game Sudoku được tạo thành từ 9x9 ô vuông (9 dòng và 9 cột). Giả sử mình tách dòng đầu tiên của bảng game này ra đứng riêng biệt:

Nó lại trở thành mảng 1 chiều có 9 phần tử.

Vậy, mảng một chiều khi mô phỏng nó bằng hình ảnh, chúng ta chỉ thấy được 1 hàng ngang có nhiều cột phân chia thành các ô (tượng trưng cho các ô nhớ trong máy tính). Còn khi chúng ta nhìn vào mảng hai chiều, chúng ta thấy có nhiều hàng, mỗi hàng lại có nhiều cột, đặc biệt hơn là số lượng cột ở mỗi hàng đều bằng nhau.

Ký hiệu mình đang sử dụng ở đây khá phù hợp với những biến trong JavaScript: [y][x], tất cả các mảng đều bắt đầu từ 0, do vậy có thể hiểu nôm na về dạng câu hỏi: “Khoảng cách bao nhiêu tính từ phía trái” hoặc “vị trí 0” sẽ chính xác là tọa độ đầu tiên từ bên trái.

Một trong những quy ước chung được sử dụng rộng rãi khi áp dụng với ma trận là dùng chung biến x và y, ví dụ x luôn luôn là chỉ số cột (khoảng cách, vị trí tính từ bên trái), và y là chỉ sổ dòng (khoảng cách từ trên xuống). Do vậy, tọa độ y,x tương ứng với [0][0] là thành phần đầu tiên ở góc trên bên trái, [0][1] là thành phần thứ 2 tiếp theo, [1][n] là dòng thứ nhất cột n,....

Javascript và 2D Array

Nhưng trên thực tế, JavaScript lại không hỗ trợ 2D Array. Và cách thường sử dụng để xử lý dữ liệu trong mảng 2 chiều là tạo đối tượng Array, bao gồm nhiều đối tượng Array bên trong. 

Sử dụng mảng của mảng

Cách sử dụng mảng 2 chiều trong JavaScript là tạo mảng 1 chiều, sau đó gán từng đối tượng bên trong đó với 1 mảng 1 chiều khác. Nếu đi vào việc phân tích cụ thể, chức năng dưới đây là 1 trong những cách đơn giản để tạo và cố định mảng 2 chiều:

as2D= new Array(); // an array of "whatever"
 as2D[0]= new Array("a","b","c","d","e","f","g","h","i","j" );
 as2D[1]= new Array("A","B","C","D","E","F","G","H","I","J" );
 as2D[2]= new Array("!","@","#","$","%","^","&","*","(",")" );

Khi đó, chúng ta đã có thể xây dựng và xác định được mảng dữ liệu với 3 đối tượng, mỗi đối tượng có 10 chuỗi ký tự khác nhau. Và bây giờ, tiếp tục sử dụng cú pháp JavaScript để truy cập như bình thường:

alert( as2D[0][0] ); // displays a
alert( as2D[2][2] ); // displays @
alert( as2D[2][9] ); // displays (

Sử dụng [...]

Cú pháp:

var arr = [ item0, item1, item2, ... ]

là cách viết tắt của:

var arr = new Array( item0, item1, item2,... );

Qua đó, chúng ta có thể hiểu rằng:

[] tương tự với mảng mới và không có dữ liệu 

["item0"] tương tự với mảng mới với 1 chuỗi dữ liệu 

["item0","item1"] tương tự với mảng mới với 2 chuỗi dữ liệu

Do đo, các bạn có thể xác định và xây dựng mảng dữ liệu như trên bằng cú pháp:

var as2D = [ 
 ["a","b","c","d","e","f","g","h","i","j"], 
 ["A","B","C","D","E","F","G","H","I","J"], 
 ["!","@","#","$","%","^","&","*","(",")"] 
 ];

Với cú pháp như vậy, JavaScript có thể dễ dàng xây dựng được biến theo dạng mảng, tương tự như cú pháp:

as2D[n]= new Array( a,b,c,... )

đã được sử dụng trước đó. Và cách truy cập dữ liệu cũng không có gì khác.

Tạo mảng hai chiều (2D Array)

Sử dụng vòng lặp for:

Lý do chính để tạo và sử dụng mảng 2 chiều là tại một thời điểm hoặc vị trí nào đó trong toàn bộ chương trình, chúng ta bắt buộc phải dùng các cấu trúc lệnh lặp nhau. Ví dụ:

for ( var y=0; y<3; y++ ) {
   for ( var x=0; x<5; x++ ) { 
       // do something with Array[y][x]
   }
}

Và quá trình này để phục vụ chương trình khi đi qua từng dòng và cột để truy cập dữ liệu tại những vị trí tương ứng. Ví dụ:

var sOut="<table border=2>";
   for (var y=0; y<as2D.length; y++ ) { // for each row
      sOut += "<tr>";
      for (var x=0; x<as2D[y].length; x++ ) { // for each clm
         sOut += "<td>" + as2D[y][x] + "</td>";
      }
       sOut += "</tr>";
   }
   sOut += "</table>";

sẽ tạo ra trang HTML có dạng như hình dưới:

Và nếu thay đổi vị trí của dòng và cột cho nhau:

var nClmsPerRow= as2D[0].length; // assume same length
   for ( var x=0; x<nClmsPerRow; x++ ) { // for each row
      sOut += "<tr>";
      for ( var y=0; y<as2D.length; y++ ) { // for each clm
         sOut += "<td>" + as2D[y][x] + "</td>";
      }
      sOut += "</tr>";
   }

Thì bảng của chúng ta sẽ có 10 dòng và 3 cột:

Sử dụng lệnh lặp for...in:

JavaScript còn cung cấp cho người sử dụng cấu trúc lặp lệnh khá đặc biệt thông qua mảng dữ liệu, đó là hàm for... in. Việc sử dụng chức năng này khá đơn giản khi đã biết rõ về điều kiện kết thúc vòng lặp (phần cuối cùng trong mảng dữ liệu). Và nó được sử dụng cùng với Collection và Array. Với Array thì cú pháp chung sẽ có dạng:

for ( value in aArray )

Mỗi 1 vòng lặp sẽ thiết lập Value thành chỉ số lặp đi lặp lại (0, 1, 2,...), và quy trình này sẽ kết thúc khi tới vị trí cuối cùng trong mảng. Dưới đây là 1 vài đoạn mã có chức năng truy cập tới tất cả các thành phần trong ví dụ mảng 2 chiều bên trên:

for ( y in as2D ) {
   for ( x in as2D[y] ) {
      // do something with as2D[y][x];
   }
}

Phần giá trị thực của for...in sẽ xuất hiện khi chúng ta có sparse array ; cụ thể là trường hợp một số thành phần chưa được xác định rõ. Ví dụ như sau:

var aSparse= new Array;
 aSparse[0]= ["zero", "one", "two" ];
 aSparse[4]= [ , "forty-one", ];
 aSparse[5]= ["fifty", "fifty-one", "fifty-two"];
 for ( y in aSparse ) {
    for ( x in aSparse[y] ) {
       alert("y,x=(" +y+ "," +x+ ") value: " + aSparse[y][x] );
    }
 }

sẽ bỏ qua các dòng từ 1 > 3, cột 0 và 2 của dòng 4, toàn bộ giá trị trong đây sẽ không được xác định. Và kết quả trả về tại đây sẽ có dạng:

y,x=(0,0) = 0
y,x=(0,1) = 1
y,x=(0,2) = 2
y,x=(4,1) = 40 – 1 
y,x=(5,0) = 50
y,x=(5,1) = 50 – 1 
y,x=(5,2) = 50 – 2

Một số hàm xử lý mảng trong Javascript

Việc xử lý mảng trong Javascript đóng vai trò rất quan trọng vì nó được sử dụng khá nhiều trong thực tế. Chính vì vậy việc biết một số hàm xử lý mảng thông dụng trong Javascript sẽ giúp bạn dễ dàng học cũng như tìm hiểu Javascript hơn.

1. Array.push()

Hàm push() khi được áp dụng vào các đối tượng sẽ thực hiện chức năng gán đối tượng (hoặc chuỗi) mới tới vị trí cuối cùng. Cách này thường được dùng để xác định 1 mảng nào đó từ khởi đầu, chúng ta có thể sử dụng cú pháp:

var as2D = new Array();
 as2D[0] = new Array();
 as2D[0].push( "a" );
 as2D[0].push( "b" );
 as2D[0].push( "c","d","e","f","g","h","i" );
 as2D[0].push( "j" );
 as2D.push( new Array( "A","B","C","D","E","F","G","H","I","J" ) );
 as2D.push( [ "!","@","#","$","%","^","&","*","(",")" ] ); 

Cú pháp trên được dùng để tạo đối tượng có dạng mảng trong mảng, và cách thức hoạt động tương tự như ví dụ trên. Tuy nhiên, các bạn cần lưu ý rằng hàm push() cho phép người dùng dồn các phần dữ liệu đơn (như dòng 3,4 và 6) hoặc dữ liệu kép (dòng 5), còn dòng 7 và 8 sẽ dồn toàn bộ các dữ liệu vào vị trí top của mảng. Chúng ta có thể thấy sự khác biệt so với ví dụ trên khi không có minh họa:

var as2D= []; // or: new Array();
 as2D.push( ["a","b","c","d","e","f","g","h","i","j"] );
 as2D.push( ["A","B","C","D","E","F","G","H","I","J"] );
 as2D.push( ["!","@","#","$","%","^","&","*","(",")"] ); 

2. String.split()

Hàm split() của đối tượng String trong JavaScript sẽ trả về đối tượng Array, và rất được sử dụng thường xuyên trong việc cố định Array với các biến đã được khởi tạo trước:

var sData1= "a,b,c,d,e,f,g,h,i,j";
var sData2= "A,B,C,D,E,F,G,H,I,J";
var sData3= "!,@,#,$,%,^,&,*,(,)";
var as2D= []; // or: new Array();
 as2D[0]= sData1.split(",");
 as2D[1]= sData2.split(",");
 as2D[2]= sData3.split(",");

Tham số thứ 2 trong hàm split() có chức năng xác nhận tất cả các ký tự phân cách, trong trường hợp này mình sử dụng dấu phẩy. Có 1 quy luật như sau: nếu ký tự phân cách có dạng rỗng (“”), thì kết quả trả về sẽ là mảng dữ liệu cá ký tự riêng biệt.

var sData1= "abcdefghij";
var sData2= "ABCDEFGHIJ";
var sData3= "[email protected]#$%^&*()";
var as2D= []; // or: new Array();
 as2D[0]= sData1.split("");
 as2D[1]= sData2.split("");
 as2D[2]= sData3.split("");

Hoặc:

var as2D= []; 
 as2D[0]= "abcdefghij".split("");
 as2D[1]= "ABCDEFGHIJ".split("");
 as2D[2]= "[email protected]#$%^&*()".split("");

Hoặc thậm chí là:

var as2D= [
 "abcdefghij".split(""),
 "ABCDEFGHIJ".split(""),
 "[email protected]#$%^&*()".split("")
 ];

Nếu đem so sánh đoạn mã cuối cùng với C++ thì JavaScript có một chút khác biệt: việc khai báo var chỉ là 1 phần của thủ tục được thực hiện trong quá trình thực thi.

Ngoài ra, các bạn có thể tự tìm hiểu thêm về các hàm xử lý mảng có sẵn trong Javascript như: valueOf(), pop(), splice(), sort(),...

Tạm kết

Trên đây mình đã giới thiệu cho các bạn về mảng 2 chiều, các thao tác để tạo và truy cập cũng như một số hàm xử lý mảng 2 chiều trong Js. Bạn thấy thế nào về JS, hãy đưa ra những ý kiến trong quá trình sử dụng js nhé. Nếu các bạn thấy bài viết hữu ích hãy rate 5* và share cho mọi người tham khảo!

Hãy để lại comment để mình có thể hoàn thiện bản thân hơn trong tương lai. Cám ơn các bạn!