📊 Mảng Đa Chiều - Multi-Dimensional Arrays
Chào mừng đến với bài học về Multi-Dimensional Arrays - cách quản lý bảng 2 chiều trong Café!
🎯 Món Ăn Hôm Nay
Tưởng tượng bạn đang quản lý quán cà phê:
- Bảng giá theo tuần → Mảng 2 chiều (7 ngày × 5 món)
 - Sơ đồ bàn → Mảng 2 chiều (hàng × cột)
 - Quản lý dữ liệu dạng bảng → Hiệu quả hơn
 
Đó chính là Multi-Dimensional Arrays - mảng của mảng!
📊 Multi-Dimensional Array Là Gì?
Mảng 2 chiều = Bảng có hàng và cột (mảng của mảng)
// Bảng giá: 3 ngày × 3 món
int[][] bangGia = {
    {45000, 50000, 55000},  // Ngày 1
    {46000, 51000, 56000},  // Ngày 2
    {45000, 49000, 54000}   // Ngày 3
};
// Truy cập: bangGia[hàng][cột]
int gia = bangGia[0][1];  // Hàng 0, cột 1 → 50000
☕ Ẩn Dụ Café:
- Mảng 2D = Bảng menu trên tường
 - Hàng = Ngày trong tuần
 - Cột = Các món đồ uống
 - Phần tử = Giá của món tại ngày cụ thể
 
🔢 Index Mảng 2D
int[][] data = {
    {10, 20, 30},
    {40, 50, 60}
};
// data[hàng][cột]
data[0][0]  // 10
data[0][1]  // 20
data[1][2]  // 60
👨🍳 Câu Chuyện Trong Quán
Tình huống 1: Sơ Đồ Bàn
public class SoDoban {
    public static void main(String[] args) {
        // 0 = Trống, 1 = Có khách
        int[][] soDoBan = {
            {1, 0, 1},  // Hàng 1
            {0, 1, 0},  // Hàng 2
            {1, 1, 0}   // Hàng 3
        };
        System.out.println("🪑 SƠ ĐỒ BÀN:\n");
        for (int hang = 0; hang < soDoBan.length; hang++) {
            System.out.print("Hàng " + (hang + 1) + ": ");
            
            for (int cot = 0; cot < soDoBan[hang].length; cot++) {
                if (soDoBan[hang][cot] == 1) {
                    System.out.print("🔴 ");  // Có khách
                } else {
                    System.out.print("⚪ ");  // Trống
                }
            }
            System.out.println();
        }
    }
}
Output:
🪑 SƠ ĐỒ BÀN:
Hàng 1: 🔴 ⚪ 🔴 
Hàng 2: ⚪ 🔴 ⚪ 
Hàng 3: 🔴 🔴 ⚪
Tình huống 2: Doanh Thu Tuần
public class DoanhThuTuan {
    public static void main(String[] args) {
        String[] ngay = {"T2", "T3", "T4", "T5", "T6", "T7", "CN"};
        String[] buoi = {"Sáng", "Trưa", "Tối"};
        
        int[][] doanhThu = {
            {50000, 80000, 100000},   // T2
            {55000, 85000, 110000},   // T3
            {60000, 90000, 120000},   // T4
            {58000, 88000, 115000},   // T5
            {65000, 95000, 130000},   // T6
            {120000, 150000, 180000}, // T7
            {130000, 160000, 190000}  // CN
        };
        System.out.println("📊 DOANH THU TUẦN:\n");
        System.out.printf("%-5s", "");
        for (String b : buoi) {
            System.out.printf("%12s", b);
        }
        System.out.println("\n" + "━".repeat(41));
        for (int i = 0; i < ngay.length; i++) {
            System.out.printf("%-5s", ngay[i]);
            for (int j = 0; j < buoi.length; j++) {
                System.out.printf("%,12d", doanhThu[i][j]);
            }
            System.out.println();
        }
    }
}
Output:
📊 DOANH THU TUẦN:
          Sáng       Trưa        Tối
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
T2          50,000      80,000     100,000
T3          55,000      85,000     110,000
T4          60,000      90,000     120,000
T5          58,000      88,000     115,000
T6          65,000      95,000     130,000
T7         120,000     150,000     180,000
CN         130,000     160,000     190,000
📝 Công Thức Nấu (Code Examples)
Ví Dụ 1: Khai Báo Mảng 2D
public class KhaiBaoMang2D {
    public static void main(String[] args) {
        // Cách 1: Khởi tạo trực tiếp
        int[][] gia1 = {
            {45000, 50000},
            {55000, 60000}
        };
        // Cách 2: Khai báo rồi gán
        int[][] gia2 = new int[2][2];
        gia2[0][0] = 45000;
        gia2[0][1] = 50000;
        gia2[1][0] = 55000;
        gia2[1][1] = 60000;
        // Cách 3: Mảng jagged (hàng có độ dài khác nhau)
        int[][] gia3 = new int[2][];
        gia3[0] = new int[]{45000, 50000, 55000};  // 3 phần tử
        gia3[1] = new int[]{60000, 65000};         // 2 phần tử
        System.out.println("Giá [0][1]: " + gia1[0][1]);
    }
}
Ví Dụ 2: Duyệt Mảng 2D
public class DuyetMang2D {
    public static void main(String[] args) {
        String[][] menu = {
            {"Espresso", "Latte", "Mocha"},
            {"Cappuccino", "Americano", "Macchiato"}
        };
        System.out.println("☕ MENU 2 TẦNG:\n");
        // Duyệt với for loop
        for (int i = 0; i < menu.length; i++) {
            System.out.println("Tầng " + (i + 1) + ":");
            for (int j = 0; j < menu[i].length; j++) {
                System.out.println("  " + (j + 1) + ". " + menu[i][j]);
            }
            System.out.println();
        }
        // Duyệt với for-each
        System.out.println("FOR-EACH:\n");
        for (String[] tang : menu) {
            for (String mon : tang) {
                System.out.print(mon + " ");
            }
            System.out.println();
        }
    }
}
Ví Dụ 3: Tính Tổng Mảng 2D
public class TinhTongMang2D {
    public static void main(String[] args) {
        int[][] doanhThu = {
            {100000, 150000, 200000},  // Tuần 1
            {120000, 160000, 210000},  // Tuần 2
            {110000, 155000, 205000},  // Tuần 3
            {130000, 170000, 220000}   // Tuần 4
        };
        System.out.println("📊 DOANH THU THÁNG:\n");
        int tongThang = 0;
        for (int tuan = 0; tuan < doanhThu.length; tuan++) {
            int tongTuan = 0;
            
            System.out.print("Tuần " + (tuan + 1) + ": ");
            for (int ngay = 0; ngay < doanhThu[tuan].length; ngay++) {
                tongTuan += doanhThu[tuan][ngay];
            }
            
            System.out.printf("%,d VND%n", tongTuan);
            tongThang += tongTuan;
        }
        System.out.println("━".repeat(30));
        System.out.printf("TỔNG THÁNG: %,d VND%n", tongThang);
    }
}
Output:
📊 DOANH THU THÁNG:
Tuần 1: 450,000 VND
Tuần 2: 490,000 VND
Tuần 3: 470,000 VND
Tuần 4: 520,000 VND
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TỔNG THÁNG: 1,930,000 VND
Ví Dụ 4: Tìm Giá Trị Lớn Nhất
public class TimMaxMang2D {
    public static void main(String[] args) {
        int[][] soBan = {
            {10, 15, 20},  // Espresso, Latte, Mocha
            {25, 30, 18},  // Sáng, Trưa, Tối
            {12, 22, 28}
        };
        String[] mon = {"Espresso", "Latte", "Mocha"};
        String[] buoi = {"Sáng", "Trưa", "Tối"};
        int max = soBan[0][0];
        int maxHang = 0, maxCot = 0;
        for (int i = 0; i < soBan.length; i++) {
            for (int j = 0; j < soBan[i].length; j++) {
                if (soBan[i][j] > max) {
                    max = soBan[i][j];
                    maxHang = i;
                    maxCot = j;
                }
            }
        }
        System.out.println("🏆 BÁN CHẠY NHẤT:");
        System.out.println("Số lượng: " + max + " ly");
        System.out.println("Buổi: " + buoi[maxHang]);
        System.out.println("Món: " + mon[maxCot]);
    }
}
Ví Dụ 5: Ma Trận Vuông (NxN)
public class MaTranVuong {
    public static void main(String[] args) {
        int[][] maTran = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        System.out.println("📐 MA TRẬN 3×3:\n");
        // In ma trận
        for (int i = 0; i < maTran.length; i++) {
            for (int j = 0; j < maTran[i].length; j++) {
                System.out.printf("%3d", maTran[i][j]);
            }
            System.out.println();
        }
        // Tính tổng đường chéo chính
        int tongCheoChinh = 0;
        for (int i = 0; i < maTran.length; i++) {
            tongCheoChinh += maTran[i][i];  // [0][0], [1][1], [2][2]
        }
        System.out.println("\nTổng đường chéo chính: " + tongCheoChinh);
    }
}
Output:
📐 MA TRẬN 3×3:
  1  2  3
  4  5  6
  7  8  9
Tổng đường chéo chính: 15
Ví Dụ 6: Mảng Jagged (Không Đều)
public class MangJagged {
    public static void main(String[] args) {
        // Mỗi hàng có số cột khác nhau
        String[][] khuVuc = {
            {"Bàn 1", "Bàn 2"},                    // Khu A: 2 bàn
            {"Bàn 3", "Bàn 4", "Bàn 5"},          // Khu B: 3 bàn
            {"Bàn 6", "Bàn 7", "Bàn 8", "Bàn 9"}  // Khu C: 4 bàn
        };
        System.out.println("🏢 SƠ ĐỒ KHU VỰC:\n");
        for (int i = 0; i < khuVuc.length; i++) {
            System.out.print("Khu " + (char)('A' + i) + ": ");
            
            for (int j = 0; j < khuVuc[i].length; j++) {
                System.out.print(khuVuc[i][j]);
                if (j < khuVuc[i].length - 1) {
                    System.out.print(", ");
                }
            }
            System.out.println();
        }
    }
}
Output:
🏢 SƠ ĐỒ KHU VỰC:
Khu A: Bàn 1, Bàn 2
Khu B: Bàn 3, Bàn 4, Bàn 5
Khu C: Bàn 6, Bàn 7, Bàn 8, Bàn 9
🔥 Thực Hành Trong Quán
Bài Tập 1: Bảng Giá Theo Size
public class BangGiaSize {
    public static void main(String[] args) {
        String[] mon = {"Espresso", "Latte", "Mocha"};
        String[] size = {"S", "M", "L"};
        
        int[][] gia = {
            {35000, 40000, 45000},  // Espresso
            {40000, 45000, 50000},  // Latte
            {45000, 50000, 55000}   // Mocha
        };
        System.out.println("💰 BẢNG GIÁ THEO SIZE:\n");
        
        System.out.printf("%-12s", "");
        for (String s : size) {
            System.out.printf("%10s", s);
        }
        System.out.println("\n" + "━".repeat(42));
        for (int i = 0; i < mon.length; i++) {
            System.out.printf("%-12s", mon[i]);
            for (int j = 0; j < size.length; j++) {
                System.out.printf("%,10d", gia[i][j]);
            }
            System.out.println();
        }
    }
}
Output:
💰 BẢNG GIÁ THEO SIZE:
                 S         M         L
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Espresso        35,000    40,000    45,000
Latte           40,000    45,000    50,000
Mocha           45,000    50,000    55,000
Bài Tập 2: Quản Lý Kho Theo Tuần
public class QuanLyKhoTuan {
    public static void main(String[] args) {
        String[] sanPham = {"Cà phê", "Sữa", "Đường"};
        String[] ngay = {"T2", "T3", "T4", "T5", "T6"};
        
        int[][] tonKho = {
            {50, 48, 45, 42, 40},  // Cà phê (kg)
            {30, 28, 32, 30, 28},  // Sữa (lít)
            {20, 19, 18, 22, 20}   // Đường (kg)
        };
        System.out.println("📦 TỒN KHO TUẦN:\n");
        for (int i = 0; i < sanPham.length; i++) {
            System.out.println(sanPham[i] + ":");
            
            for (int j = 0; j < ngay.length; j++) {
                System.out.printf("  %s: %2d", ngay[j], tonKho[i][j]);
                
                // Cảnh báo nếu < 25
                if (tonKho[i][j] < 25) {
                    System.out.print(" ⚠️");
                }
                System.out.println();
            }
            System.out.println();
        }
    }
}
Bài Tập 3: Tính Trung Bình Từng Hàng/Cột
public class TinhTrungBinh {
    public static void main(String[] args) {
        int[][] diem = {
            {8, 9, 7},   // Nhân viên 1
            {7, 8, 9},   // Nhân viên 2
            {9, 9, 8}    // Nhân viên 3
        };
        
        String[] nhanVien = {"Minh", "Lan", "Hoa"};
        String[] tieuChi = {"Phục vụ", "Pha chế", "Vệ sinh"};
        System.out.println("⭐ ĐÁNH GIÁ NHÂN VIÊN:\n");
        // Tính trung bình từng nhân viên
        for (int i = 0; i < nhanVien.length; i++) {
            int tong = 0;
            for (int j = 0; j < diem[i].length; j++) {
                tong += diem[i][j];
            }
            double trungBinh = (double) tong / diem[i].length;
            System.out.printf("%s: %.1f điểm%n", nhanVien[i], trungBinh);
        }
        System.out.println("\n📊 TRUNG BÌNH TỪNG TIÊU CHÍ:\n");
        // Tính trung bình từng tiêu chí
        for (int j = 0; j < tieuChi.length; j++) {
            int tong = 0;
            for (int i = 0; i < diem.length; i++) {
                tong += diem[i][j];
            }
            double trungBinh = (double) tong / diem.length;
            System.out.printf("%s: %.1f điểm%n", tieuChi[j], trungBinh);
        }
    }
}
⚠️ Lỗi Thường Gặp
Lỗi 1: Nhầm Hàng Và Cột
// ❌ SAI: Nhầm thứ tự hàng/cột
int[][] data = {{1, 2}, {3, 4}};
int value = data[1][0];  // Hàng 1, cột 0 → 3
// Nếu nghĩ ngược: cột 1, hàng 0 → SAI!
Lỗi 2: Quên Kiểm Tra Chiều Dài
// ❌ SAI: Giả định tất cả hàng có cùng độ dài
int[][] jagged = {{1, 2}, {3, 4, 5}};
for (int i = 0; i < jagged.length; i++) {
    for (int j = 0; j < jagged[0].length; j++) {  // ❌ Lỗi tại hàng 2!
        System.out.print(jagged[i][j]);
    }
}
// ✅ ĐÚNG: Kiểm tra từng hàng
for (int i = 0; i < jagged.length; i++) {
    for (int j = 0; j < jagged[i].length; j++) {  // ✅ OK
        System.out.print(jagged[i][j]);
    }
}
Lỗi 3: Khởi Tạo Sai
// ❌ SAI: Chỉ tạo mảng hàng, chưa tạo mảng cột
int[][] data = new int[3][];
data[0][0] = 10;  // ❌ NullPointerException!
// ✅ ĐÚNG: Tạo cả hàng và cột
int[][] data = new int[3][3];
data[0][0] = 10;  // ✅ OK
Lỗi 4: Nhầm Length
int[][] data = {{1, 2, 3}, {4, 5, 6}};
// data.length → Số hàng (2)
// data[0].length → Số cột hàng 0 (3)
// data[1].length → Số cột hàng 1 (3)
💡 Bí Quyết Của Barista
- arr[hàng][cột]: Hàng trước, cột sau
 - arr.length: Số hàng
 - arr[i].length: Số cột của hàng i
 - Mảng jagged: Mỗi hàng có thể khác độ dài
 - Nested loop: Vòng ngoài = hàng, vòng trong = cột
 - Kiểm tra bounds: Luôn check length trước khi truy cập
 
🎓 Bạn Đã Học Được
- ✅ Mảng 2D = Mảng của mảng (bảng)
 - ✅ Khai báo: 
type[][] name = {{...}, {...}} - ✅ Truy cập: 
arr[hàng][cột] - ✅ Duyệt với nested loop (2 vòng for)
 - ✅ Mảng jagged (không đều)
 - ✅ Tính tổng, tìm max, trung bình
 - ✅ Ứng dụng: Bảng giá, sơ đồ, ma trận
 
☕ Món Tiếp Theo
Đã biết mảng đa chiều! Giờ học về ArrayList:
💡 Lời Khuyên Cuối: Mảng 2D như bảng menu treo tường - dễ nhìn, dễ tìm khi sắp xếp hàng/cột rõ ràng!