Bài tập VBA cho người mới bắt đầu

Liên hệ QC

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia
8/6/06
Bài viết
14,320
Được thích
22,361
Nghề nghiệp
Nuôi ba ba & trùn quế
Các bạn viết cho 1 macro để ta có được kết quả như bảng sau:

2/29/2004​
2/29/2016​
2/29/2000​
2/29/2012​
2/29/2024​
2/29/2008​
2/29/2020​
2/29/2032​
2/29/2044​
2/29/2028​
2/29/2040​
2/29/2052​
2/29/2036​
2/29/2048​
2/29/2060​
2/29/2072​
2/29/2056​
2/29/2068​
2/29/2080​
2/29/2064​
2/29/2076​
2/29/2088​
2/29/2084​
2/29/2096​
2/29/2092​
 
Có bắt buộc phải format m/d/yyyy hôn cha?
 
Upvote 0
Lên Copilot hỏi thì đước trả lời là: Những năm nhuận của thế kỷ 21...
(= những năm có tháng Hai 29 ngày )
Thử viết bằng VBA nhưng không ra kết quả như hình trên...
Có lẽ Bác nên đổi lại là VBA nâng cao...
Thử bằng Power Query... và thu được kết quả sau.

let
// Generate a list of years from 2000 to 2099
yearList = {2000..2099},

// Filter the list to include only leap years
leapYears = List.Select(yearList, each Date.IsLeapYear(_)),

// Create a list of dates with February 29th from leap years
feb29Dates = List.Transform(leapYears, each #date(_, 2, 29)),
#"Converted to Table" = Table.FromList(feb29Dates, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Changed Type" = Table.TransformColumnTypes(#"Converted to Table",{{"Column1", type date}})
in
#"Changed Type"
 

File đính kèm

  • LeapYear.xlsx
    16.2 KB · Đọc: 5
Lần chỉnh sửa cuối:
Upvote 0
Với kết quả y như bảng trên? Quá sức với người mới bắt đầu VBA.
(b2) Xin các bạn xài 2 vòng lặp; Vòng ngoài là 7 & vòng trong là từ 2000 step 1 cho đến 2099
(b1) Trước đó khai báo 1 biến mảng (1 → 99, 1 → 7)
(b3) Vòng lặp bên trong ta tìm tham biến Dat - là ngày theo hàm DateSerial() để biết thứ của ngày 29/2 của năm đang khảo sát;
(b4) Từ số liệu về thứ (trong tuần) của Dat ta gán Dat vô đúng cột mà nó phải có vô mảng (. . . )
Chuyên khó nhất là tăng chỉ số dòng đúng cho cột cần gán Dat

Có bắt buộc phải format m/d/yyyy hôn cha?
/(hông buộc bác ạ!; Nó sao để vậy cũng được nha, mấy anh chị em (muốn sử dụng thời giờ rỗi trong mấy ngày Tết NĐ)!

/(ết quả có thể là vầy cũng OK:

2/29/2004​
2/29/2032​
2/29/2060​
2/29/2088​
2/29/2016​
2/29/2044​
2/29/2072​
2/29/2000​
2/29/2028​
2/29/2056​
2/29/2084​
2/29/2012​
2/29/2040​
2/29/2068​
2/29/2096​
2/29/2024​
2/29/2052​
2/29/2080​
2/29/2008​
2/29/2036​
2/29/2064​
2/29/2092​
2/29/2020​
2/29/2048​
2/29/2076​
 
Upvote 0
(b2) Xin các bạn xài 2 vòng lặp; Vòng ngoài là 7 & vòng trong là từ 2000 step 1 cho đến 2099
(b1) Trước đó khai báo 1 biến mảng (1 → 99, 1 → 7)
(b3) Vòng lặp bên trong ta tìm tham biến Dat - là ngày theo hàm DateSerial() để biết thứ của ngày 29/2 của năm đang khảo sát;
(b4) Từ số liệu về thứ (trong tuần) của Dat ta gán Dat vô đúng cột mà nó phải có vô mảng (. . . )
Chuyên khó nhất là tăng chỉ số dòng đúng cho cột cần gán Dat


/(hông buộc bác ạ!; Nó sao để vậy cũng được nha, mấy anh chị em (muốn sử dụng thời giờ rỗi trong mấy ngày Tết NĐ)!

/(ết quả có thể là vầy cũng OK:

2/29/2004​
2/29/2032​
2/29/2060​
2/29/2088​
2/29/2016​
2/29/2044​
2/29/2072​
2/29/2000​
2/29/2028​
2/29/2056​
2/29/2084​
2/29/2012​
2/29/2040​
2/29/2068​
2/29/2096​
2/29/2024​
2/29/2052​
2/29/2080​
2/29/2008​
2/29/2036​
2/29/2064​
2/29/2092​
2/29/2020​
2/29/2048​
2/29/2076​
Bài này có lẽ 1 vòng lặp cũng được
2000 là năm nhuận, 4 năm 1 lần nhuận, step 4 chắc cũng vẫn được
 
Upvote 0
Thế kỷ 21 bắt đầu ngày 01/01/2001 và chấm dứt 31/12/2100
 
Upvote 0
Các bạn viết cho 1 macro để ta có được kết quả như bảng sau:

2/29/2004​
2/29/2016​
2/29/2000​
2/29/2012​
2/29/2024​
2/29/2008​
2/29/2020​
2/29/2032​
2/29/2044​
2/29/2028​
2/29/2040​
2/29/2052​
2/29/2036​
2/29/2048​
2/29/2060​
2/29/2072​
2/29/2056​
2/29/2068​
2/29/2080​
2/29/2064​
2/29/2076​
2/29/2088​
2/29/2084​
2/29/2096​
2/29/2092​
Bác Sa ơi không biết có đúng ý bác không nhưng cháu thấy kết quả đúng bác có thưởng gì cho học sinh mới ăn tết không ạ.
Mã:
Sub abc()
    Dim i As Long, arr, kq, a As Integer, b As Integer
    arr = Array(3, 1, 6, 4, 2, 7, 5)
    ReDim kq(1 To 4, 1 To 7)
    For i = 1 To 25
        a = (i - 1) Mod 7
        b = (i - 1) \ 7 + 1
        kq(b, arr(a)) = "29/2/" & (i * 4 + 1996)
    Next i
    Range("A1").Resize(4, 7).Value = kq
End Sub
 
Upvote 0
Với kết quả y như bảng trên? Quá sức với người mới bắt đầu VBA.
Lão ta nhầm lẫn giữa tập VBA và tập phân tích giải thuật.

Bài này giải thuật dễ nhất là phân tích chu kỳ mẫu (pattern recognition)
1. Liệt kê những năm nhuần trong thế kỷ 21, tức là từ 2001 đến 2099.
2. Sắp xếp lại theo thứ tự của đề bài.

Bắt đầu từ A1, ta lấy năm đầu tiên, tức 2004.
A2 = A1 + 28 năm
...
A5 = A4 + 28 năm = 2116 (>=2100); đem trừ 100 và chuyển qua B1
B1 = 2016
tiếp tục cho đến khi gặp lại 2004 thì dừng.

Đây là mảng 2 chiều. Muốn một hay hai vòng lặp chả thành vấn đề. Hai vòng lặp thì dùng số cột số dòng. Một vòng thì dùng con toán chuyển đổi chỉ số mảng 1 chiều sang 2 chiều.
 
Upvote 0
Giải thuật đơn giản mới khó chứ code vòng lặp là chuyện căn bản. Lập luận như sau:
1. Lặp bao nhiêu
- Từ 2001 đến 2003 không có năm nhuận. Năm nhuận đầu tiên là 2004
- Cách 4 năm mới có 1 năm nhuận (mới có 29/02)
Vậy thì vòng lặp i 25 lần, từ 2004 đến 2100 (step 4)

2. Kích thước bảng kết quả
Cấu trúc kết quả là bảng 7 cột, suy ra số dòng tối đa là 4. Vậy thì khai báo mảng 4 dòng 7 cột. Tuy vậy tôi cứ khai 10 dòng 7 cột, lý do thì xem mục 4 bên dưới.

3. Biện pháp tìm vị trí cột cho 29/02: Dùng DateSerial(i ,2, 29), weekday của nó là bao nhiêu thì bỏ vào cột bấy nhiêu. Suy luận 1 chút cho thứ 2 là đầu tuần nhưng cột 2. Nếu chủ nhật là đầu tuần thì khỏi phân vân. Mod 7 và thương số nguyên chia 7 chỉ là ăn may, trừ khi biết chắc điều gì đó của năm 2000. Tuy nhiên năm 2000 không phải của thế kỷ 21 nên không được dựa vào năm này.

4. Vị trí cột nào đã điền thì phải điền sang dòng kế, quy luật 100% cho việc tăng dòng tự động (*) là không biết chắc nên không thả nổi. Làm sao biết chắc khi chỉ dựa vào phép toán chia 7? (**)

(*) Tăng dòng tự động là tin rằng dòng nào cũng đầy đủ 7 ô, trước khi qua dòng kế. Tôi không chắc.
(**) bài 9 đưa ra 1 chu kỳ 28 năm, nếu đúng thì phải tính toán mới ra 28, và phải chắc chắn rằng đúng cho mọi thế kỷ, mọi thiên niên kỷ. Tôi không chắc.
Và bởi vì không chắc mà lại lười tính toán, nên tôi cho VBA tính giùm.
 
Lần chỉnh sửa cuối:
Upvote 0
Dùng vòng for với bước nhảy 28
Mã:
Sub XYZ()
  Dim res(1 To 4, 1 To 7), i&, k&, j&
  For i = 4 To 28 * 25 Step 28
    j = i \ 100 + 1
    k = (i Mod 100)
    res(k \ 28 + 1, j) = "29/2/" & k + 2000
  Next i
  Range("A1").Resize(4, 7).Value = res
End Sub
 
Upvote 0
Bài 1 & bài 5: các năm nhuận liên tiếp được xếp cùng dòng hoặc cùng cột. code dưới viết theo bài 1
Mã:
Option Explicit

Sub zzz()
Dim Kq()
Dim i, j, k

k = 2099 \ 4
ReDim Kq(1 To k, 1 To 7)

i = 1
For k = 2000 To 2099 Step 4
    j = Weekday(DateSerial(k, 2, 29))
    Kq((i - 1) \ 7 + 1, j) = DateSerial(k, 2, 29)
    i = i + 1
Next k
Sheet1.Range("A6").Resize((i - 1) \ 7 + 1, 7) = Kq
End Sub
 
Upvote 0
Bác Sa ơi không biết có đúng ý bác không nhưng cháu thấy kết quả đúng bác có thưởng gì cho học sinh mới ăn tết không ạ.
Kết quả là text. Nếu tính từ 2100 đến 2199 thì xuất hiện 29/02/2100 trong khi đó năm 2100 không nhuận. Thứ tự trong tuần không còn đúng nữa: Hai cột đầu tiên là thứ sáu và thứ bảy.

1707116047531.png
Dùng vòng for với bước nhảy 28
Nếu tính từ 2100 đến 2199 thì cũng xuất hiện 29/02/2100, và thứ tự trong tuần không đúng nữa: Hai cột đầu tiên là thứ sáu và thứ bảy.

1707115883212.png

Bài 1 & bài 5: các năm nhuận liên tiếp được xếp cùng dòng hoặc cùng cột. code dưới viết theo bài 1
Nếu tính từ 2100 đến 2199 thì cũng xuất hiện 29/02/2100, do dùng DateSerial nên chuyển thành 01/03/2100, ở cột 2, sau đó bị ghi đè bởi 29/02/2112.
 
Lần chỉnh sửa cuối:
Upvote 0
Kết quả là text. Nếu tính từ 2100 đến 2199 thì xuất hiện 29/02/2100 trong khi đó năm 2100 không nhuận. Thứ tự trong tuần không còn đúng nữa: Hai cột đầu tiên là thứ sáu và thứ bảy.

View attachment 298960

Nếu tính từ 2100 đến 2199 thì cũng xuất hiện 29/02/2100, và thứ tự trong tuần không đúng nữa: Hai cột đầu tiên là thứ sáu và thứ bảy.

View attachment 298959


Nếu tính từ 2100 đến 2199 thì cũng xuất hiện 29/02/2100, do dùng DateSerial nên chuyển thành 01/03/2100, ở cột 2, sau đó bị ghi đè bởi 29/02/2112.
Theo như số liệu bài 1 & 5, tính từ 2000 đến 2099, cứ 7 lần nhuận liên tiếp liền nhau sẽ có thứ trong tuần khác nhau, quy luật này chạy code thấy có vẻ đúng.
Sang số liệu khác, có thể quy luật này không còn đúng nữa. Việc này liên quan tới trình bày các kết quả tính trong bảng, để bác @SA_DQ cho ý kiến rồi sẽ xử lý tiếp vậy
 
Upvote 0
Các bạn cứ làm theo yêu cầu của đề bài; Chuyện còn lại người ra đề gánh với đời!

Cảm ơn tất cả các bạn đã, đang & sẽ viết bài trong mục này

Chúc các bạn vui xuân khỏe mạnh & hạnh phúc!
 
Upvote 0
Mới bắt đầu là phải thế lày các bác ạ,
1 là phải dùng hàm có sẵn của excel vì có biết lặp thế lào đâu.
2 là gặp lỗi phải dùng thần chú resume next.

Thêm: nhờ bài này mới biết năm 2096 đến 2104 là 8 năm mới xuất hiện năm nhuận. Ai mà cứ 4 là sai liền. --=0 --=0 --=0

Mã:
Option Explicit

Sub zzz()
    Dim day As Date
    Dim j&, Hang&, Cot&, HangMax&
    Dim ArrNgay(1 To 1000, 1 To 7) As Variant
    On Error Resume Next
    For Cot = 1 To 7
        Hang = 0
        For j = 2000 To 2100 Step 4
            day = CDate("2/29/" & j)
            If Application.Weekday(day, 1) = Cot Then
                Hang = Hang + 1
                ArrNgay(Hang, Cot) = day
                HangMax = Application.Max(Hang, HangMax)
            End If
        Next
    Next
    Range("A1").Resize(HangMax, 7).Value = ArrNgay
End Sub
 
Upvote 0
Giải thuật nhảy 28 năm là giải thuật theo nhìn trực diện vào mảng.

Nếu nhìn vào bên trong dữ liệu thì phân tích sẽ gồm thứ trong tuần:

Code theo phân tích này thì rất giản dị:
Sub t()
Dim a(1 To 4, 1 To 7)
Dim r(1 To 7) As Long ' chỉ định hàng hiện tại của mỗi cột
For yr = 2000 To 2100 - 1 Step 4 ' 2100 thuộc về thế kỷ 22
dt = DateSerial(yr, 2, 29) ' tất cả các năm chia chẵn 4 trong thế kỷ này đều nhuần
cl = Weekday(dt) ' thứ trong tuần tức là chỉ số cột
r(cl) = r(cl) + 1 ' chỉ cần tìm thêm dòng là xong
a(r(cl), cl) = dt
Next yr
[a1].Resize(4, 7) = a
End Sub
 
Upvote 0
Upvote 0
For yr = 2000 To 2100 - 1 Step 4 ' 2100 thuộc về thế kỷ 22
2100 thuộc về thế kỷ 22, vậy theo anh năm 100 thuộc thế kỷ thứ 2, và thế kỷ thứ nhất chỉ có 99 năm? Nghĩa là tôi sai năm sáu chục năm nay?
Vì tôi chỉ có thể nói 2100 không có trong đề bài ở bài 1.
Thực ra bài 1 không rõ ràng:
- bảng 7 cột không có tiêu đề và mạnh ai nấy suy diễn ra thứ trong tuần.
- Các con số trong bảng phải suy diễn ra là ngày tháng (kiểu Mỹ)
- Phải suy diễn 1 chút nữa rằng các năm của thế kỷ 20 khi năm lớn nhất nhìn thấy là 2096, năm nhỏ nhất là 2004, (suy diễn thế kỷ là của bài 4, không phải tôi)

Và bởi vì đề bài ra không có 2100 (là 1 mốc quan trọng vì năm không nhuận), nên mợt số các bài giải cho kết quả là text, vẫn đúng với hình ảnh nhìn thấy ở bài 1, và diễn giải lại ở bài 5
 
Upvote 0
Web KT
Back
Top Bottom