Chương 5 – Mảng

4. Duyệt qua các phần tử của mảng

Khi làm việc với mảng, rất thường xuyên chúng ta cần phải duyệt qua các phần tử của mảng. Có một số cách khác nhau để duyệt mảng, trong đó 2 cách phổ biến là sử dụng vòng lặp for hoặc sử dụng phương thức forEach của mảng.

Duyệt mảng với vòng lặp for

Khi sử dụng vòng lặp for, chúng ta thực hiện việc đếm biến chạy từ vị trí số 0, tức là vị trí của phần tử đầu tiên, đến vị trí số n – 1, tức là vị trí của phần tử cuối cùng.

Ví dụ:

1.	let fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
2.	let text = '';
3.	for(let index = 0; index < fruits.length; index++) {
4.	   text += fruits[index] + '<br/>';
5.	}

Kết quả:

Banana
    Orange
    Apple
    Mango

Trong đó, vòng lặp for chạy biến đếm từ số 0 đến số 3 tức là vị trí của phần tử cuối cùng.

Duyệt mảng với phương thức forEach

Một cách khác để duyệt qua các phần tử của mảng đó là sử dụng phương thức forEach của mảng. Phương thức này nhận vào tham số là một hàm (chúng ta sẽ tìm hiểu về hàm trong chương sau), trong đó có các phần tử của mảng.

Ví dụ:

1.	var numbers = [4, 9, 16, 25];
2.	numbers.forEach(function(item) {
3.	   document.write(item + '<br/>');
4.	});

Kết quả:

    4

    9

    16

    25

Trong ví dụ này, lần lượt 4 phần tử của mảng sẽ được duyệt qua và hiển thị lên tài liệu. Biến item lần lượt đại diện cho từng phần tử của mảng, từ phần tử đầu tiên cho đến phần tử cuối cùng.

5. Mảng nhiều chiều

Phần tử của một mảng có thể là một mảng khác. Khi này chúng ta có mảng nhiều chiều. Có thể có mảng 2 chiều, 3 chiều… hoặc nhiều hơn. Mảng càng nhiều chiều thì độ phức tạp khi xử lý càng cao.

Truy cập phần tử của mảng nhiều chiều

Mảng một chiều cần 1 chỉ số để xác định vị trí của phần tử mảng.

Mảng hai chiều cần 2 chỉ số để xác định vị trí của phần tử mảng

Mảng 3 chiều cần 3 chỉ số để xác định vị trí của phần tử mảng

Mảng hai chiều

Mảng hai chiều là mảng nhiều chiều được sử dụng phổ biến. Mảng hai chiều là một mảng mà có mỗi phần tử là một mảng một chiều. Có thể coi mảng hai chiều là một bảng gồm n dòng và m cột:

Mảng trên có 3 dòng và 4 cột, tổng cộng 12 phần tử, các phần tử đó sẽ được truy cập theo chỉ số từ [0][0], [0][1],… đến [2][3].

Khởi tạo mảng hai chiều

Để khởi tạo mảng hai chiều, chúng ta có thể sử dụng các cặp dấu ngoặc vuông, trong đó mỗi dòng được khai báo như là một mảng một chiều. Trong ví dụ sau, chúng ta khai báo một mảng hai chiều bao gồm 3 dòng và 3 cột. Mỗi dòng được khai báo như một mảng một chiều.

1.	let cities = [
2.		["Hanoi","Saigon","DaNang"],
3.		["New York","California","Miami"],
4.		["Tokyo","Nagofa","Osaka"]
5.	];

Cách thứ 2 để khai báo mảng hai chiều đó là sử dụng từ khoá new như minh hoạ trong ví dụ sau:

1.	let cities = new Array(3);
2.	for (let i = 0; i < 3; i++) {
3.	    cities[i] = new Array(3);
4.	}
5.	cities[0][0] = "Hanoi";
6.	cities[0][1] = "Saigon";
7.	cities[0][2] = "DaNang";
8.	cities[1][0] = "New York";
9.	cities[1][1] = "California";
10.	cities[1][2] = "Miami";
11.	cities[2][0] = "Tokyo";
12.	cities[2][1] = "Nagofa";
13.	cities[2][2] = "Osaka";

Cả hai cách này đều cho kết quả giống nhau, nhưng cách thứ 2 này rườm rà hơn, do đó chúng ta thường sử dụng cách thứ nhất để khởi tạo mảng.

Duyệt mảng đa chiều

Để duyệt phần tử của mảng đa chiều, chúng ta sử dụng các vòng lặp lồng nhau. Ví dụ dưới đây sử dụng 2 vòng lặp lồng nhau để duyệt mảng hai chiều đã khai báo ở trên.

1.	for (let i = 0; i < cities.length; i++) {
2.	    for (let j = 0; j < cities[i].length; j++) {
3.	        document.write(cities[i][j] + "<br>");
4.	    }
5.	}

6. Các giải thuật với mảng

Mảng là một cấu trúc được sử dụng nhiều trong các ứng dụng, và cũng có rất nhiều các thao tác khác nhau có thể thực hiện với mảng. Trong phần này, chúng ta sẽ cùng liệt kê một số thao tác cơ bản và thường thấy khi làm việc với mảng.

Khởi tạo giá trị ngẫu nhiên cho các phần tử

Ví dụ:

1.	let matrix = new Array(10, 10);
2.	for (let row = 0; row < matrix.length; row++) {
3.	   for (let column = 0; column < matrix[row].length; column++) {
4.	       matrix[row][column] = Math.floor((Math.random() * 100) + 1);
5.	   }
}

Trong ví dụ này, chúng ta đã sử dụng hàm random() của lớp Math để sinh ra các số ngẫu nhiên nằm trong khoảng từ 0 đến 100.

Tính tổng các phần tử số

Ví dụ:

1.	let total = 0;
for (let row = 0; row < matrix.length; row++) {
2.	   for (let column = 0; column < matrix[row].length; column++) {
3.	       total += matrix[row][column];
4.	   }
5.	}

Trong ví dụ này, biến total lưu trữ giá trị của tổng tất cả các phần tử. Ban đầu biến total có giá trị là 0, sau đó nó lần lượt “tích luỹ” thêm giá trị của từng phần tử. Đến cuối cùng, giá trị của total chính là tổng của tất cả các phần tử.

Tính tổng các phần tử số theo từng cột

Ví dụ

1.	for (let column = 0; column < matrix[0].length; column++) {
2.	   let total = 0;
3.	   for (let row = 0; row < matrix.length; row++){
4.	       total += matrix[row][column];
5.	   }
6.	   console.log("Sum for column " + column + " is " + total);
7.	}

Trong ví dụ này, biến total được dùng để lưu trữ giá trị tổng của các phần tử trong từng cột. Khác với ví dụ trước đó, trong ví dụ này biến total được khai báo ở trong vòng lặp đầu tiên, và như vậy sau mỗi lần lặp thì biến này lại được khai báo lại và có giá trị là 0.

Tìm hàng có tổng lớn nhất

Ví dụ:

1.	let maxRow = 0;
2.	let indexOfMaxRow = 0;
3.	for (let column = 0; column < matrix[0].length; column++) {
4.	   maxRow += matrix[0][column];
5.	}
6.	for (let row = 1; row < matrix.length; row++) {
7.	   let totalOfThisRow = 0;
8.	   for (let column = 0; column < matrix[row].length; column++) {
9.	       totalOfThisRow += matrix[row][column];
10.	  }
11.	  if (totalOfThisRow > maxRow) {
12.	      maxRow = totalOfThisRow;
13.	     indexOfMaxRow = row;
14.	 }
}
console.log("Row " + indexOfMaxRow + " has the maximum sum of " + maxRow);

Trong ví dụ này, biến maxRow được dùng để lưu trữ giá trị tổng lớn nhất. Biến indexOfMaxRow được dùng để lưu trữ chỉ số của dòng có tổng giá trị lớn nhất. Biến totalOfThisRow được dùng để lưu trữ tổng giá trị của từng dòng.

Trộn ngẫu nhiên các phần tử

Ví dụ:

  1. for (let row = 0; row < matrix.length; row++) {
  2.   for (let column = 0; column < matrix[row].length; column++) {
  3.      let randomRow = parseInt(Math.random() * matrix.length);
  4.      let randomColumn = parseInt(Math.random() * matrix[row].length);
  5.      let temp = matrix[row][column];
  6.      matrix[row][column] = matrix[randomRow][randomColumn];
  7.      matrix[randomRow][randomColumn] = temp;
  8.   }
  9. }

Trong ví dụ này, chúng ta sử dụng hàm random() của lớp Math để sinh ra ngẫu nhiên các giá trị dòng và cột. Sau đó thực hiện phép hoán đổi giá trị của các phần tử ngẫu nhiên tại vị trí dòng và cột đó.

Sao chép phần tử của mảng

1.	let sourceArray = [2, 3, 1, 5, 10];
2.	let targetArray = new Array(sourceArray.length);
for (let i = 0; i < sourceArray.length; i++) {
3.	   targetArray[i] = sourceArray[i];
4.	}

Trong ví dụ này, chúng ta tạo một mảng targetArray có độ dài bằng với độ dài của mảng sourceArray. Sau đó, chúng ta duyệt qua lần lượt từng phần tử của mã sourceArray và gán giá trị của phần tử đó cho từng phần tử tương ứng của mảng targetArray.

Bài tập thực hành