Đố chơi đầu năm

Liên hệ QC
Xin các bạn giúp tôi sửa vài câu lệnh làm sao để rút gọn (BỎ BỚT) khoảng trên ba câu lệnh trong macro trong #19 sau:
Đoán đại
Mã:
Function SumIf_22(Ma As String, CSDL As Range)
Dim Arr()
Dim J As Long, Tong As Double, SoChia As Integer, DD As Integer, VTr As Integer
 
For J = 1 To CSDL.Rows.Count
    VTr = InStr(CSDL.Cells(J, 1).Value, Ma)
    DD = Len(CSDL.Cells(J, 1).Value)  '** '
    If VTr Then
        Tong = Tong + CSDL.Cells(J, 2).Value * 6 / (DD + 1)
    End If
Next J
SumIf_22 = Tong
End Function
 
Mình cảm ơn bạn CHAOQUAY 3 lần luôn vì đã giúp mình:
Thứ nhất: Rút bớt các câu lệnh trong hàm để hàm thanh thoát hơn;
Thứ nhì: Giúp mình phát hiện ra 1 'lỗi' trong hàm mình viết, một khi ta cung cấp tham biến Ma là trị rỗng thì kết quả sai;
Thứ ba: Từ đấy mình bắt chước & tìm ra cách rút gọn trên nền tảng tương tự::
PHP:
Function SumIf_22(Ma As String, CSDL As Range)
 Dim J As Long, Tong As Double, SoChia As Integer, DD As Integer, VTr As Integer
 
 If Ma = Space(0) Then
    SumIf_22 = "Mã NV":                   Exit Function
 End If
 For J = 1 To CSDL.Rows.Count
    VTr = InStr(CSDL.Cells(J, 1).Value, Ma)        '   '
    DD = Len("@" & CSDL.Cells(J, 1).Value)
    If VTr Then
        SoChia = DD / 6
        Tong = Tong + CSDL.Cells(J, 2).Value / SoChia
    End If
 Next J
 SumIf_22 = Tong
End Function
 
[Giành cho những người mới bắt đầu VBA]​

Thực hiện macro để có kết quả như trong hình
 

File đính kèm

  • 29 Thg 02.jpg
    29 Thg 02.jpg
    21.9 KB · Đọc: 39
[Giành cho những người mới bắt đầu VBA]​

Thực hiện macro để có kết quả như trong hình
[Giành cho những người mới bắt đầu lập trình]
(tức là không nhất thiết phải VBA)

Phân tích xem yêu cầu của cái hình trên là gì. Và các bước chính để đáp ứng những yêu cầu ấy.
 
Tôi đang thắc mắc ngôn ngữ lập trình khác (không phải VBA) có gọi là macro không?
Có.
Hồi tôi học Assembly Language của PDP-11 (DEC) thì một nhóm lệnh có thể được gộp thành một Macro. Đại khái như một Sub.

Và trong C thì Macro có vị trí rõ rệt. Trích GNU:

1644501159979.png
 
[Giành cho những người mới bắt đầu VBA]​
Cách 1 dễ: Dùng 2 vòng lặp và 1 mảng trung gian hoặc dùng sheet làm trung gian. Dễ đối với người suy luận kiểu phân bước. Tôi thuộc loại này.
Cách 2 cũng dễ: 1 vòng lặp duy nhất, bỏ qua trung gian, dễ đối với người có tư duy trừu tượng. Tôi trừu tượng dở nên làm cách 1 trước rồi tìm cách rút gọn bớt 1 vòng lặp sau.
 
Nếu là 19 giá trị cụ thể cách nhau (4 * 365 + 1) = 1461 ngày, rải vào 19 ô như hình thì dùng phương pháp cần cù thôi - nhập giá trị lần lượt vào 19 ô.
Mã:
Sub ngay_cuoi_thang2_nam_nhuan()
Dim k As Long, c As Long, kq(1 To 3, 1 To 7)
    c = 5
    For k = 1 To 19
        kq((k - 1) \ 7 + 1, (c + 34) Mod 7 + 1) = DateSerial(2024 + (k - 1) * 4, 2, 29)
        c = c - 2
    Next k
    Range("A2:G4") = kq
End Sub
 
Nếu chỉ với 19 năm nhuận theo hình
Mã:
Sub ABC()
  Dim i&, ngay As Date
  For i = 1 To 19
    ngay = DateSerial(2024 + (i - 1) * 4, 2, 29)
    Cells((i - 1) \ 7 + 1, Weekday(ngay)) = ngay
  Next i
End Sub
 
Có thể xài vòng lặp (?):
Mã:
 Dim J As Long, Dat As Date
 For J = 2024 To 2099 Step 4
'    . . . . . .  '
'  . . . . . . . .    '  
 Next J

Toàn là các 'Cộm cán' không hà!
 
Cách 1
PHP:
Sub nhuan()
Dim ArrS(1 To 19, 1 To 2), k As Long

For i = 2024 To 2096 Step 4
    k = k + 1
    ArrS(k, 1) = DateSerial(i, 2, 29)
    ArrS(k, 2) = Weekday(ArrS(k, 1))
Next

For i = 1 To 19
    n = ArrS(i, 2) + 3
    k = Cells(100, n).End(xlUp).Row + 1
    Cells(k, n).Value = ArrS(i, 1)
Next
End Sub
Cách 2
PHP:
Sub nhuan2()
For i = 2024 To 2096 Step 4
    n = Weekday(DateSerial(i, 2, 29)) + 3
    k = Cells(100, n).End(xlUp).Row + 1
    Cells(k, n).Value = DateSerial(i, 2, 29)
Next
End Sub
 
Cách 1
PHP:
Sub nhuan()
Dim ArrS(1 To 19, 1 To 2), k As Long

For i = 2024 To 2096 Step 4
    k = k + 1
    ArrS(k, 1) = DateSerial(i, 2, 29)
    ArrS(k, 2) = Weekday(ArrS(k, 1))
Next

For i = 1 To 19
    n = ArrS(i, 2) + 3
    k = Cells(100, n).End(xlUp).Row + 1
    Cells(k, n).Value = ArrS(i, 1)
Next
End Sub
Cách 2
PHP:
Sub nhuan2()
For i = 2024 To 2096 Step 4
    n = Weekday(DateSerial(i, 2, 29)) + 3
    k = Cells(100, n).End(xlUp).Row + 1
    Cells(k, n).Value = DateSerial(i, 2, 29)
Next
End Sub
Êêê, sáng kiến mới là đố vui trên bàn nhậu chứ Weekday thì là đi thi rồi. :D
 
Lần chỉnh sửa cuối:
Mã:
(c + 34) Mod 7 + 1)
Tôi bó tay vụ lấy đâu ra con 5, con 34 và cộng 1. Anh vừa sáng kiến vừa mà mắt người ta
Khởi đầu bằng 5 vì giá trị đầu tiên (năm 2024) phải đập vào cột 5 theo hình.

Theo dõi ta có các năm 2024, 2028, ... được nhập vào các cột 5, 3, 1, 6, 4, 2, 7, 5, 3, 1, 6, 4, 2, 7, 5, 3, 1, 6, 4 (chu kỳ 5, 3, 1, 6, 4, 2, 7) *. Từ đó có ý tưởng c = c - 2 và dùng MOD.

Trong trường hợp cần xác định chỉ số cột thì thực ra là (c - 1) Mod 7 + 1.

Nhưng nếu thế thì từ lúc c ÂM thì chỉ số cũng sẽ ra ÂM. Vì thế cộng thêm với bội của 7 để chỉ số DƯƠNG. Nhưng phải cộng tới 35 *** tất cả các chỉ số mới DƯƠNG

(c - 1 + 35) Mod 7 + 1 = (c + 34) Mod 7 + 1

*: Ta coi CN là 1, xuất phát từ 5 và đi ngược chiều kim đồng hồ, sau CN là 7 (thứ 7) - kiểu đi vòng tròn, thì ta luôn phải nhẩy 2 bước. Vì thế sau 1 (CN) là 6 (thứ 6), sau 2 (thứ 2) là 7 (thứ 7).

***: Giá trị c cuối cùng là c = 5 - 2*18 = -31 -> c - 1 = -32, vậy phải cộng thêm ít nhất là 35. Cộng thêm bội của 7 mà > 35 cũng được.
 
Lần chỉnh sửa cuối:
Trong vòng lặp của #30 ta có thể xài 2 dòng lệnh thiệt rùa, như sau:

Dat = DateSerial(J, 2, 29)
Cells(100, 3 + Weekday(Dat)).End(xlUp).Offset(1).Value = Dat

[Con số 3 là tùy thích của mỗi người]
 
Trong vòng lặp của #30 ta có thể xài 2 dòng lệnh thiệt rùa, như sau:

Dat = DateSerial(J, 2, 29)
Cells(100, 3 + Weekday(Dat)).End(xlUp).Offset(1).Value = Dat
Em muốn viết tường minh cho người nào cũng hiểu 1 cách dễ dàng. Gộp lệnh không phải lúc nào cũng rõ ràng, dễ đọc dễ sửa
 
Điều kiện là "mới bắt đầu" mà quý vị đốt giai đoạn dữ quá. Lúc vừa thấy câu đó, tôi đã nghi là quý vị sẽ chơi toàn những bài tính toán chỉ số mảng cho nên mới ra thêm phần "phân tích bằng lời" (bài #24).
@Bác tác giả bài #34:
Nếu người học có khả năng toán như bác thì người ta đã học lên đến trình độ cao như những người góp code khác rồi.
@các tác giả khác (tức những người góp bài):
Quý vị quen cách tính nhẩm giải thuật rồi cho nên làm dễ dàng. Quý vị quen rằng nếu không giải thích thì người mới học sẽ chả hiểu gì cả. Bài này thực ra có 3 bước mà quý vị tính nhẩm 2 bước đầu:
1. Đọc kỹ cái hình. Nhận định cái pattern và khám phá ra cái hình đó nó trưng bày những dữ liệu gì.
2. Suy tính cách thực hiện. Nghiên cứu những thuật toán, những công cụ trợ giúp.
3. Viết code.
(thực ra lập trình thực tế còn bước thứ tư là test lại xem mình có đúng ở những bước 1, 2, rồi 3. Nếu khong đúng thì phải bắt đầu lại. Bài này khá dễ - tức khá ít output, và output dạng "cứng" cho nên bước thứ tư này không quan trọng)

Trong một đồ án tầm cỡ, cả 4 bước tôi đều có lập tư liệu (documentation) đàng hoàng, với đầy đủ chỉ tiêu (metrics, benchmarks)

Thôi thì không ai nhã hứng nên tôi làm luôn cho các bạn mới học lập trình theo dõi:

Phân tích dưới đây là nói về cái hình ở bài #23:

1. Output là một cái bảng trên Excel Sheet
1.1. Bảng có dòng tiêu đề là tên 7 ngày trong tuần, đặt thành 7 cột, bắt đầu là ngày chúa nhật. (điểm này các code của quý vị đã đưa ra thiếu hết. Phần output chỉ có ngày và hiểu ngầm là sắp xếp theo thứ)
1.2. Dữ liệu trong bảng là các ngày 29 tháng 2. Vì vậy chỉ có thể là các năm nhuần.
1.3. Giới hạn: ngày nhỏ nhất trong bảng là năm 2024. Ngày lớn nhất là năm 2096.
Như vậy, bài toán bao gồm liệt kê các ngày 29 tháng 2 kể từ thời gian hiện tại đến cuối thể kỷ (2099, hay 2100 cũng vậy thôi). Liệt kê theo bảng 7 cột, biểu thị theo các thứ tuần, bắt đầu là chủ nhật.

2. Giải thuật gồm hai phần, phần tính các năm nhuần và phần trình bày.
2.1. Có hai cách tính, cách biết sẵn và cách tính trâu bò.
2.1.1. Cách biết sẵn: biết năm nhuần gần đây nhất là 2024, và cứ 4 năm lại nhuần. Giải thuật là vòng lặp bắt đầu từ đấy (bài #31) cho đên 2099. Hoặc đi thêm một bước nữa thì biết từ đây đến cuối thế kỷ còn 19 lần và dùng số đại diện 1-19 (bài #28, #29).
2.1.2. Cách trâu bò: bắt đầu từ năm nay, tính đến năm 2099. Cứ năm nào có ngày 20/02 thì lấy ra.
2.1.2.1. Dùng hàm Cdate(năm & "02-29") và bẫy lỗi.
2.2. Cách trình bày thì cũng tuỳ thuộc vào cách tính ở trên.
2.2.1. Nếu biết sẵn thì ceiling(19/7) = 3. Và dùng một mảng 7x3. Dùng con tính như bài #28,#29 để tính ra chỉ số.
2.2.2. Nếu trâu bò thì dựng một mảng 7 phần tử cho biết vị trí dòng trống của mỗi cột. Cứ tính ngày ra thứ nào thì dựa theo đó mà chép xuống.

3. Viết code. Để chiều rảnh tính tiếp.
 
Điều kiện là "mới bắt đầu" mà quý vị đốt giai đoạn dữ quá. Lúc vừa thấy câu đó, tôi đã nghi là quý vị sẽ chơi toàn những bài tính toán chỉ số mảng cho nên mới ra thêm phần "phân tích bằng lời" (bài #24).
Tôi có đọc bài 24, tôi biết bài ấy chứa 1 yêu cầu phải "nhìn hình đoán chữ" trước khi giải, và cũng biết rằng tác giả bài 24 muốn giải thích từ gốc đến ngọn nên tôi để dành cho bác ấy đấy chứ. Thế nên bài 27 tôi chỉ gợi ý mà chưa viết code, khi thấy bài 28 và 29 viết code cao siêu quá nên tôi mới ngứa tay viết 1 code loại dễ hiểu liền kề.
 
khi thấy bài 28 và 29 viết code cao siêu quá
Nhìn hình thì biết tất cả đều là ngày cuối cùng của tháng 2 của 19 năm nhuận liên tiếp. Nhưng thứ tự các năm nhuận không đúng với thứ tự đi trong mảng là từ dòng đầu tới cuối, trong mỗi dòng từ cột đầu tới cuối. Vì thế không thể dùng vòng FOR đơn giản mà phải tính toán chỉ số dòng cột dành cho các năm LIÊN TIẾP. Nhìn hình thì cũng thấy về chỉ số cột thì luôn lùi 2 bước, nhưng là đi "theo vòng tròn". Tức từ 1 sang 6 và từ 2 sang 7. Xuất phát từ cột 5 luôn lùi 2 bước sẽ có chuỗi 5, 3, 1, 6, 4, 2, 7 lặp lại.

Code có cao siêu gì đâu. Chẳng qua là anh thấy "cờ" đang vuột khỏi tay anh, người ta đang phất cờ lia lịa. Vì thế anh sốt ruột mà lao vào thôi. :D

Điều kiện là "mới bắt đầu" mà quý vị đốt giai đoạn dữ quá. Lúc vừa thấy câu đó, tôi đã nghi là quý vị sẽ chơi toàn những bài tính toán chỉ số mảng cho nên mới ra thêm phần "phân tích bằng lời" (bài #24).
@Bác tác giả bài #34:
Đây là đố vui. Nếu là đi thi thì lại khác. Còn trên bàn nhậu người ta đố liên tiếp nhiều trò, kể liên tiếp nhiều câu chuyện cười, tiếu lâm. Cứ đủng đỉnh như bác thì người ta đi tăng 2 tăng 3 rồi bác vẫn còn ngồi nghiền ngẫm lời giải, suy nghĩ xem có nên cười hay không.
Thực ra là tôi tham gia thôi. Không có ý định giúp ai hiểu. Nếu tôi làm gia sư, đang giảng bài thì lại khác.
 
...
Đây là đố vui. Nếu là đi thi thì lại khác. Còn trên bàn nhậu người ta đố liên tiếp nhiều trò, kể liên tiếp nhiều câu chuyện cười, tiếu lâm. Cứ đủng đỉnh như bác thì người ta đi tăng 2 tăng 3 rồi bác vẫn còn ngồi nghiền ngẫm lời giải, suy nghĩ xem có nên cười hay không.
...
Lúc đi "chén chú chén anh", tôi vẫn đi chung với một người bạn khác. Vào tới bàn là hai tôi phá lên cười như nắc nẻ. Những người khác trong bàn thắc mắc hỏi thì tôi trả lời:
- À, tôi cười những câu chuyện tếu các bác kể lần trước. Đến hôm nay tôi mới hiểu.
- Thế còn thằng B. Nó vốn thông minh lắm mà. Cũng phải đến nay mới cười được sao?
- Không, nó cười trước các câu chuyện mấy bác kể hôm nay đấy.

...
Thực ra là tôi tham gia thôi. Không có ý định giúp ai hiểu. Nếu tôi làm gia sư, đang giảng bài thì lại khác.
Bác ngứa tay code. Tôi thì ngứa mồm giảng. :p
Chỉ cần tay vả mồm hay mồm cắn tay thì cả hai đều hết ngứa?
 
Web KT
Back
Top Bottom