Bài tập VBA đơn giản dành cho người mới bắt đầu [Phần 2]

Liên hệ QC

ChanhTQ@

0901452không62
Tham gia
5/9/08
Bài viết
4,256
Được thích
4,863
Xin các bạn có bài tập nào hay hay đăng lên để cùng nhau luyện cho mau tiến bộ nhe!
Mình xin mở màn bài đầu:
ĐỀ BÀI 1:

Tôi có bảng số liệu từ cột [A..E] như sau:

| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W 2 |HoTen|Date1|Date2|Date3|Date4|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18
3 |Hồ Lễ|3|5|7|13|Do|Do|Do|Xh|Xh|Vg|Vg|Tm|Tm|Tm|Tm|Tm|Tm||.|||
4 |Đỗ Nè|4|8|13|15|Nu|Nu|Nu|Nu|Xh|Xh|Xh|Xh|Xm|Xm|Xm|Xm|Xm|Dn|Dn|||
5 |Vũ Xe|2|4|12|13|Do|Do|Vg|Vg|Nu|Nu|Nu|Nu|Nu|Nu|Nu|Nu|Hg|||.|||

Phần từ cột [F] trở đi là phần cần viết 1 macro để nó tô màu nền khác nhau theo những giá trị cùng dòng từ cột [B..E];
Màu tô do bạn tự chọn, cốt fân biệt giữa chúng & dịu mắt là được!


PHẦN TỔNG HỢP CÁC ĐỀ BÀI TẬP:

Tên|Tóm tắc|Bài thứ
Đề bài 1|Tô màu theo trị số các ô bên trái cùng dòng| #1
Đề bài 1A|Lọc theo các số cần thiết từ các chuỗi số| #73
Đề bài 1B|Xác định loại tam giác dựa trên 3 số ngẫu nhiên được tạo ra| #82
Đề bài 2|Lập danh sách học sinh theo từng lớp| #11
Đề bài 2A|Dịch ngôn ngữ VBA sang tiếng Việt| #19
BĐT(*)|Lập danh sách các nữ HS có ngày sinh trong 1 quí| #101
Đề bài 3|Thống kế kết quả điểm của từng lớp theo từng môn học| #22
Đề bài 4|Lập danh sách HS các lớp đạt điểm cực trị của từng môn| #46
Đề bài 4A|Tìm trong danh sách thí sinh, số báo danh nào có tổng điểm các môn cao nhất| #94
Đề bài 5|Thống kê từng khoảng điểm của môn học| #58
Đề bài 6|Thống kê điểm trung bình theo giới tính| #71

(*) BĐT: Bài đọc thêm

.
.
.
 
Lần chỉnh sửa cuối:
Không xài công thức + không dùng vòng lặp thì khó lắm, hay viết các lệnh 12 lần?
 
Upvote 0
Bài tập: Tìm cách xài lại lịch 6 tờ của năm 1999

Mình có 6 tờ lịch thật đẹp & có giá trị cao gồm 12 tháng của năm 1.999 (nhưng không có đề năm)

Mình muốn tính xem năm nào sau đó có thể xài lại tờ lịch này.

Bạn nào giúp mình với nha & xin cảm ơn trước!
 
Upvote 0
Mình có 6 tờ lịch thật đẹp & có giá trị cao gồm 12 tháng của năm 1.999 (nhưng không có đề năm)

Mình muốn tính xem năm nào sau đó có thể xài lại tờ lịch này.

Bạn nào giúp mình với nha & xin cảm ơn trước!
Sao mà trùng khớp hết được bác? Nào là THỨ phải giống nhau, nào là ngày 28 hoặc 29 của tháng 2.
 
Upvote 0
Mình có 6 tờ lịch thật đẹp & có giá trị cao gồm 12 tháng của năm 1.999 (nhưng không có đề năm)

Mình muốn tính xem năm nào sau đó có thể xài lại tờ lịch này.

Bạn nào giúp mình với nha & xin cảm ơn trước!
Hic, ngồi làm thủ công vì chả có quy tắc gì để tính, thì thấy các năm có thứ, ngày, tháng giống nhau như đúc, đó là các năm: 2010 (đã qua), 2021, 2038, 2049, 2066, 2077, ... (tính tới đây thôi, không biết có sống thêm được nữa không).
 
Lần chỉnh sửa cuối:
Upvote 0
Mình có 6 tờ lịch thật đẹp & có giá trị cao gồm 12 tháng của năm 1.999 (nhưng không có đề năm)

Mình muốn tính xem năm nào sau đó có thể xài lại tờ lịch này.

Bạn nào giúp mình với nha & xin cảm ơn trước!
Em chỉ xét đến năm 2099, chắc sau đó tờ lịch đó cũng hỏng rồi.
Mã:
Sub Lich()
    Dim n&, d&, i&, arr()
    ReDim arr(1 To 100, 1 To 1)
    arr(1, 1) = 1999
    i = 1
    For n = 2000 To 2099
        d = d + IIf(n Mod 4 = 1, 2, 1)
        If (n Mod 4 <> 0) And (d Mod 7 = 0) Then
            i = i + 1
            arr(i, 1) = n
        End If
    Next
    Range("A1:A" & i) = arr
End Sub
 
Upvote 0
Hic, ngồi làm thủ công vì chả có quy tắc gì để tính, thì thấy các năm có thứ, ngày, tháng giống nhau như đúc, đó là các năm: 2010 (đã qua), 2021, 2038, 2049, 2066, 2077, ... (tính tới đây thôi, không biết có sống thêm được nữa không).
Quy tắc cũng là cách bác làm thủ công đó:tìm những năm không nhuận có ngày 1/1 là thứ 6 giống năm 1999.
 
Upvote 0
Quy tắc cũng là cách bác làm thủ công đó:tìm những năm không nhuận có ngày 1/1 là thứ 6 giống năm 1999.

(*) Ai lại đi móm cung cho chàng Nghĩa này bao giờ kia chứ!

(**) Cũng có cách khác để không qua bước tra cứu 'Năm Nhuận hay không'
 
Upvote 0
Nếu không tra cứu năm nhuận thì phải dùng hàm weekday, tra trong 100 năm lại gọi 100 lần hàm đó, tốc độ sẽ chậm hơn.
 
Upvote 0
các bậc cha chú bàn chuyện cũng tếu nhỉ . nhưng theo ngu kiến của em , dựa vào bạn tính ở bài #225 thì thầy HYen17 vui lòng đợi thêm ...404 năm nữa để xài lại tờ lịch =))
vì năm 1999 là năm Kỉ Mão . theo cách tính của bạn Hau151978 thì phải đến năm 2419 mới là năm Kỉ Mão và có thứ ngày trùng khớp với năm 1999
và khi đó các thông số tử vi trên tờ lịch theo từng ngày mới chính xác được --=0--=0--=0--=0
 
Upvote 0
các bậc cha chú bàn chuyện cũng tếu nhỉ . nhưng theo ngu kiến của em , dựa vào bạn tính ở bài #225 thì thầy HYen17 vui lòng đợi thêm ...404 năm nữa để xài lại tờ lịch =))
vì năm 1999 là năm Kỉ Mão . theo cách tính của bạn Hau151978 thì phải đến năm 2419 mới là năm Kỉ Mão và có thứ ngày trùng khớp với năm 1999
và khi đó các thông số tử vi trên tờ lịch theo từng ngày mới chính xác được --=0--=0--=0--=0
Mình không xét năm âm lịch, năm âm lịch theo can chi thì 60 năm lặp lại nhưng còn năm nhuận âm lịch thì bó tay.
Mình chỉ xét dương lịch đến năm 2099, từ 2100 trở đi thì cách tính khác.
 
Upvote 0
Nếu không tra cứu năm nhuận thì phải dùng hàm weekday, tra trong 100 năm lại gọi 100 lần hàm đó, tốc độ sẽ chậm hơn.

Nếu coi ngày nào đó là 1 điểm, thì tuần nào đó là 3 điểm, còn tháng sẽ là đường (đa số là thẳng, có vài đoạn cong) & năm sẽ là mặt fẵng.
Mà theo định đề thì qua 2 điểm ta có thể kẻ được 1 đường thẳng.
Chỉ có điều điểm thứ 2 sẽ fải từ 1/3 trở đi mà thôi.


Các bác bàn chuyện cũng tếu nhỉ . nhưng theo ngu kiến của em , dựa vào bạn tính ở bài #225 thì thầy HYen17 vui lòng đợi thêm ...404 năm nữa để xài lại tờ lịch =))
vì năm 1999 là năm Kỉ Mão . theo cách tính của bạn Hau151978 thì phải đến năm 2419 mới là năm Kỉ Mão và có thứ ngày trùng khớp với năm 1999
và khi đó các thông số tử vi trên tờ lịch theo từng ngày mới chính xác được --=0

Ừ nhỉ, vậy thêm điều kiện không chơi lịch âm mới còn đem ra xài được (ví như lịch sản xuất tại fương trời Âu-Mĩ vậy!).

Mà lịch này chỉ là 6 tờ thôi đó nha, không fải >=365 tờ đâu!
 
Upvote 0
Nếu coi ngày nào đó là 1 điểm, thì tuần nào đó là 3 điểm, còn tháng sẽ là đường (đa số là thẳng, có vài đoạn cong) & năm sẽ là mặt fẵng.
Mà theo định đề thì qua 2 điểm ta có thể kẻ được 1 đường thẳng.
Chỉ có điều điểm thứ 2 sẽ fải từ 1/3 trở đi mà thôi.
Vậy là bác so sánh weekday(dateserial(n,1,1)) và weekday(dateserial(n,3,1)) với weekday(dateserial(1999,1,1)) và weekday(dateserial(1999,3,1)). Nếu vậy thì cần dùng hàm weekday 200 lần trong vòng 100 năm.
Thực ra nếu weekday(dateserial(n+1,1,1))=weekday(dateserial(2000,1,1)) thì chắc chắn weekday(dateserial(n,3,1))=weekday(dateserial(1999,3,1)). Bởi vậy chỉ cần gọi hàm weekday(dateserial(n,1,1)) 101 lần và so sánh là đủ.
 
Upvote 0
Nếu là bài tập thì không nên cố định ở năm 1999 mà nên cho một năm bất kỳ cho tổng quát.
PHP:
Sub LichCu()
Const NamCuoi = 3000
Dim Nam As Long, WDay As Long, i As Long, Arr(1 To 1000, 1 To 1)
Nam = 1999
WDay = Weekday(DateSerial(Nam, 1, 1))
If Day(DateSerial(Nam, 3, 0)) = 29 Then
    Do
        i = i + 1
        Arr(i, 1) = Nam
        If Weekday(DateSerial(Nam + 28, 1, 1)) = WDay Then
            Nam = Nam + 28
        ElseIf Weekday(DateSerial(Nam + 40, 1, 1)) = WDay Then
            Nam = Nam + 40
        End If
    Loop Until Nam > NamCuoi
Else
    Do
        i = i + 1
        Arr(i, 1) = Nam
        If Weekday(DateSerial(Nam + 6, 1, 1)) = WDay Then
            Nam = Nam + 6
        ElseIf Weekday(DateSerial(Nam + 11, 1, 1)) = WDay Then
            Nam = Nam + 11
        ElseIf Weekday(DateSerial(Nam + 12, 1, 1)) = WDay Then
            Nam = Nam + 12
        End If
    Loop Until Nam > NamCuoi
End If
Range("A1:A" & i) = Arr
End Sub
 
Upvote 0
Đó là mô đất trên con đường VBA, ngõ hầu ai đó vấp fải í mà!

& đây là 1 tham khảo:
PHP:
Sub XaiLaiLichCu6ToCuaNam1999()
 Dim J%, fT As Integer, lT As Integer, W As Byte
 ReDim Arr(1 To 99, 1 To 1) As Integer
 
 fT = Weekday(#1/1/1999#)
 lT = Weekday(#3/13/1999#)
 For J = 2000 To 2099
    If Weekday(DateSerial(J, 1, 1)) = fT Then
        If Weekday(DateSerial(J, 3, 13)) = lT Then
            W = W + 1:      Arr(W, 1) = J
        End If
    End If
 Next J
 [AH1].Resize(W) = Arr()
End Sub

Hic, ngồi làm thủ công vì chả có quy tắc gì để tính, thì thấy các năm có thứ, ngày, tháng giống nhau như đúc, đó là các năm: 2010 (đã qua), 2021, 2038, 2049, 2066, 2077, ... (tính tới đây thôi, không biết có sống thêm được nữa không).
Cái ông gì đó ở nước Anh bị trái táo rơi vô mặt lúc ngủ mới fát hiện ra định luật 'Vạn vật hấp dẫn' mà!
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu là bài tập thì không nên cố định ở năm 1999 mà nên cho một năm bất kỳ cho tổng quát.
Kết quả như vậy không đúng đâu, năm 2112, 2140 ... là năm nhuận cũng có trong danh sách.
Mã:
Option Explicit
Function NamNhuan(ByVal n As Long) As Boolean
    NamNhuan = (n Mod 4 = 0) And ((n Mod 100 <> 0) Or (n Mod 400 = 0))
End Function


Sub LichCu()
    Dim Nam As Long, NamCuoi As Long, WDay As Long, i As Long, j As Long, NamDauNhuan As Boolean, NamTruocNhuan As Boolean, Arr()
    Nam = [A1]
    NamCuoi = [B1]
    If NamCuoi<=Nam Then End
    ReDim Arr(1 To NamCuoi - Nam, 1 To 1)
    NamDauNhuan = NamNhuan(Nam)
    NamTruocNhuan = NamDauNhuan
    For i = Nam + 1 To NamCuoi
        WDay = WDay + IIf(NamTruocNhuan, 2, 1)
        NamTruocNhuan = NamNhuan(i)
        If NamDauNhuan = NamTruocNhuan And WDay Mod 7 = 0 Then
            j = j + 1
            Arr(j, 1) = i
        End If
    Next
    Range("A2:A" & j) = Arr
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Với 6 tờ lịch đặc biệt năm 1999 của Bác SA
Theo em Bác SA có thể sử dụng tờ lịch thứ nhất vào năm sau 2016
Sau đó Bác nên cất cẩn thận để đến năm 2179 Bác mang ra xài sẽ trùng được thứ, ngày, tháng, can, chi luôn }}}}}
 
Upvote 0
Với 6 tờ lịch đặc biệt năm 1999 của Bác SA
Theo em Bác SA có thể sử dụng tờ lịch thứ nhất vào năm sau 2016
Sau đó Bác nên cất cẩn thận để đến năm 2179 Bác mang ra xài sẽ trùng được thứ, ngày, tháng, can, chi luôn }}}}}
Năm 2016 là năm nhuận còn 1999 không nhuận thì lịch trùng sao được bạn. Còn về âm lịch thì năm 2179 trùng can chi nhưng ngày âm lịch không trùng.
 
Upvote 0
Kết quả như vậy không đúng đâu, năm 2112, 2140 ... là năm nhuận cũng có trong danh sách.
Đúng là như vậy, vậy cần kiểm tra xem có phải năm nhuận không nữa.
PHP:
Sub LichCu()
Const NamCuoi = 3000
Dim Nam As Long, WDay As Long, i As Long, Arr(1 To 1000, 1 To 1)
Nam = 1999
WDay = Weekday(DateSerial(Nam, 1, 1))
If Day(DateSerial(Nam, 3, 0)) = 29 Then
    Do
        If Day(DateSerial(Nam, 3, 0)) = 29 Then
            i = i + 1
            Arr(i, 1) = Nam
        End If
        If Weekday(DateSerial(Nam + 28, 1, 1)) = WDay Then
            Nam = Nam + 28
        ElseIf Weekday(DateSerial(Nam + 40, 1, 1)) = WDay Then
            Nam = Nam + 40
        End If
    Loop Until Nam > NamCuoi
Else
    Do
        If Day(DateSerial(Nam, 3, 0)) = 28 Then
            i = i + 1
            Arr(i, 1) = Nam
        End If
        If Weekday(DateSerial(Nam + 6, 1, 1)) = WDay Then
            Nam = Nam + 6
        ElseIf Weekday(DateSerial(Nam + 11, 1, 1)) = WDay Then
            Nam = Nam + 11
        ElseIf Weekday(DateSerial(Nam + 12, 1, 1)) = WDay Then
            Nam = Nam + 12
        End If
    Loop Until Nam > NamCuoi
End If
Range("A1:A" & i) = Arr
End Sub
Các con số trong code ta tính được từ các trường hợp năm nhuận là năm tiêp theo thứ mấy từ năm đang xét.

Hoặc dễ hiểu hơn ta xét từ năm n+5 trở đi (n là năm đang xét) vì một năm không nhuận có 365 ngày, chia 7 dư 1. Trong 5 năm liên tiếp tối đa có 2 năm nhuận. Vậy để thứ của ngày 1/1 lặp lại cần tối thiểu 5 năm. Tương tự, cần tối thiểu 28 năm để có thể có một năm nhuận có thứ của ngày 1/1 lặp lại. Code như sau:
PHP:
Sub LichCu1()
Const NamCuoi = 3000
Dim Nam As Long, WDay As Long, i As Long, Arr(1 To 1000, 1 To 1)
Nam = 1999
WDay = Weekday(DateSerial(Nam, 1, 1))
If Day(DateSerial(Nam, 3, 0)) = 29 Then
    Do Until Nam > NamCuoi
        If Day(DateSerial(Nam, 3, 0)) = 29 Then
            i = i + 1
            Arr(i, 1) = Nam
        End If
        Nam = Nam + 28
        Do Until Weekday(DateSerial(Nam, 1, 1)) = WDay
            Nam = Nam + 4
        Loop
    Loop
Else
    Do Until Nam > NamCuoi
        If Day(DateSerial(Nam, 3, 0)) = 28 Then
            i = i + 1
            Arr(i, 1) = Nam
        End If
        Nam = Nam + 5
        Do Until Weekday(DateSerial(Nam, 1, 1)) = WDay
            Nam = Nam + 1
        Loop
    Loop
End If
End Sub
 
Upvote 0
Với 6 tờ lịch đặc biệt năm 1999 của Bác SA
Theo em Bác SA có thể sử dụng tờ lịch thứ nhất vào năm sau 2016
Sau đó Bác nên cất cẩn thận để đến năm 2179 Bác mang ra xài sẽ trùng được thứ, ngày, tháng, can, chi luôn }}}}}
Nếu so cả lịch âm thì tôi e là không có năm nào trùng vì nói đến lịch âm bạn cần phải so cả ngày âm lịch. 01/01/1999 = 14/11/1998AL, 01/01/2179 = 24/11/2178AL
 
Upvote 0
Năm 2016 là năm nhuận còn 1999 không nhuận thì lịch trùng sao được bạn. Còn về năm 2179 trùng can chi nhưng ngày âm không . . . .
Thì xài 1 tờ thôi mà!, nhưng đến 29/02/2016 thì cất đi cho lẹ!

Kết quả của các macro bên trên là như sau
1999
2010: 11
2021: 11
2027: 06
2038: 11
2049: 11
2055: 06
2066: 11
2077: 11
2083: 06
2094: 11
. . . . . . Thì ra có qui luật rồi!
 
Upvote 0
Web KT
Back
Top Bottom