[Bài tập vui]: Tìm ra mươi ngày 13 rơi vào thứ sáu gần hôm nay nhất!

Liên hệ QC
Lúc đầu mình cũng định đi theo hướng như vậy, nhưng 1 vài trường hợp cụ thể thì không thỏa yêu cầu & sẽ bị ai đó khó tính cự nự:

STTNgàyDel ta
112/13/19-45=T6N13(DATE(2020,1,27))
203/13/20
46
309/13/19-136
411/13/20
291​
507/13/18-563
608/13/21
564​
704/13/18-654
810/13/17-836
905/13/22
837​
1001/13/23
1082​

Chúc các bạn có mùa xuân vui vẻ & hạnh phúc!
 
Một tháng chỉ có một ngày 13. Chỉ cần lấy một lần ngày 13, sau có cứ +/- tháng (hàm DateAdd)
Em góp vui với hàm tự tạo dựa theo ý tưởng của thầy VetMini với hàm tự tạo của thầy SA_DQ :D

PHP:
Function T6N13_2(Dat As Date, Count As Long)
    ReDim Arr(1 To Count, 1 To 3)
    Dim i As Long, j As Long, Year_Dat As Long
    Dim W As Long
    i = Month(Dat)
    j = Month(Dat)
    Year_Dat = Year(Dat)
    Do Until W = Count
        If (Weekday(DateSerial(Year_Dat, i, 13))) = 6 Then
            W = W + 1
            Arr(W, 1) = W
            Arr(W, 2) = Format(DateSerial(Year_Dat, i, 13))
            Arr(W, 3) = DateDiff("d", Dat, DateSerial(Year_Dat, i, 13))
        End If
        If W = Count Then Exit Do
        If (Weekday(DateSerial(Year_Dat, j, 13))) = 6 Then
            W = W + 1
            Arr(W, 1) = W
            Arr(W, 2) = Format(DateSerial(Year_Dat, j, 13))
            Arr(W, 3) = DateDiff("d", Dat, DateSerial(Year_Dat, j, 13))
        End If
        i = i + 1: j = j - 1
    Loop
    T6N13_2 = Arr()
End Function
 
Theo thống kê thì chỉ có tháng 2 thì mệnh đề
i = i + 1:
mới vậy thôi, còn các tháng khác ta có thể
i = i + 2:
Thậm chí 1 số tháng ta có thể
i = i + 3:

Xin các bạn cho ý kiến nhận xét của mình tiếp về vấn đề này (?)
 
Lúc đầu mình cũng định đi theo hướng như vậy, nhưng 1 vài trường hợp cụ thể thì không thỏa yêu cầu & sẽ bị ai đó khó tính cự nự:
Nếu vậy thì chỉ cần xét số nào kiểm tra trước, số nào kiểm tra sau thôi, đỡ hơn là kiểm tra từng ngày.
Mã:
Function T6N13(Dat As Date)
    Dim Arr(1 To 10, 1 To 3)
    Dim a As Long, z As Long, i As Date, k As Long, d As Long, m As Long, y As Long
    d = Day(Dat):   m = Month(Dat): y = Year(Dat)
    If d < 13 Then a = -1
    z = a + 1
    Do Until k = 10
        If Dat - DateSerial(y, m + a, 13) < DateSerial(y, m + z, 13) - Dat Then
            i = DateSerial(y, m + a, 13):   a = a - 1
        Else
            i = DateSerial(y, m + z, 13):   z = z + 1
        End If
        If Weekday(i) = 6 Then
            k = k + 1:      Arr(k, 2) = Format(i, "dd/mm/yyyy")
            Arr(k, 1) = k:  Arr(k, 3) = i - Dat
        End If
    Loop
    T6N13 = Arr
End Function
 
Xài bộ lọc và vài hàm đơn giản cho nhàn! Tính từ 1900 đến 4637 luôn! :D

View attachment 265615
 
Bần đạo tu trên núi lâu quá không biết bằng hữu đàm đạo chuyện này. Thôi thì góp vui vậy. Lưu ý dùng excel phiên bản tầng thứ 9 cửu âm chân kinh 365 mới được.
Cho trước 1 ngày cột mốc nào đó (ví dụ hôm nay), Cho trước số lần tìm Thứ Sáu ngày 13 (ví dụ 10 ngày),

Danh sách các ngày thứ sáu 13 trở về trước (trước ngày cột mốc):
=LET(MyDay,$B$1-SEQUENCE(5000),MDate1,TEXT(MyDay,"DDD"),MDate2,TEXT(MyDay,"DD"),mRange,FILTER(MyDay,(MDate1="Fri")*(MDate2="13"),"Not Found"),mOrder,SEQUENCE(COUNTA(mRange)),FILTER(mRange,mOrder<=$B$2,"Not Found"))

Danh sách các ngày thứ sáu 13 trở về sau (sau ngày cột mốc):
=LET(MyDay,$B$1+SEQUENCE(5000),MDate1,TEXT(MyDay,"DDD"),MDate2,TEXT(MyDay,"DD"),mRange,FILTER(MyDay,(MDate1="Fri")*(MDate2="13"),"Not Found"),mOrder,SEQUENCE(COUNTA(mRange)),FILTER(mRange,mOrder<=$B$2,"Not Found"))

Nối 2 danh sách bên trên lại thành 1 danh sách gom bỏ vô trong 1 cột (Kiểu như "append data"):
=LET(Array1,OFFSET($A4,,,$B$2),Array2,OFFSET($B4,,,$B$2),ColToAppend,CHOOSE({1,2},Array1,Array2),FILTER(INDEX(ColToAppend,MOD(SEQUENCE(ROWS(ColToAppend)*COLUMNS(ColToAppend),,0),ROWS(ColToAppend))+1,SEQUENCE(ROWS(ColToAppend)*COLUMNS(ColToAppend),,0,1/ROWS(ColToAppend))+1),NOT(ISERROR(INDEX(ColToAppend,MOD(SEQUENCE(ROWS(ColToAppend)*COLUMNS(ColToAppend),,0),ROWS(ColToAppend))+1,SEQUENCE(ROWS(ColToAppend)*COLUMNS(ColToAppend),,0,1/ROWS(ColToAppend))+1)))))

test.jpg
 

File đính kèm

  • ChauBaThong.xlsx
    14.2 KB · Đọc: 7
Lần chỉnh sửa cuối:
Sẽ có 3 xị rượu cho ai giải đúng & sớm nhất bằng công thức!

Chúc các bạn vui vẻ & mạnh khỏe nhân dịp xuân về!
Dạo này có tuổi nên HÀM yếu lắm rồi bác, mà vẫn xin 3 xị rượu nhé bác Sa, hẹn 1 ngày gần nhất ở SG.
 
Nối 2 danh sách bên trên lại thành 1 danh sách gom bỏ vô trong 1 cột (Kiểu như "append data"):
Nếu đã có 2 danh sách ở A4 và B4 thì nối lại như sau:

=LET(db,A4#,da,B4#,rwb,ROWS(db),rwa,ROWS(da),IF(SEQUENCE(rwb+rwa)<=rwb,INDEX(db,SEQUENCE(rwb+rwa),1),INDEX(da,SEQUENCE(rwb+rwa)-rwb,1)))
 
Nếu đã có 2 danh sách ở A4 và B4 thì nối lại như sau:

=LET(db,A4#,da,B4#,rwb,ROWS(db),rwa,ROWS(da),IF(SEQUENCE(rwb+rwa)<=rwb,INDEX(db,SEQUENCE(rwb+rwa),1),INDEX(da,SEQUENCE(rwb+rwa)-rwb,1)))
Nay bần lão được thọ giáo chiêu A4# (thay cho offset) của tiên sinh, quả thật khâm phục, khâm phục!
 
Lần chỉnh sửa cuối:
Bần đạo tu trên núi lâu quá không biết bằng hữu đàm đạo chuyện này. Thôi thì góp vui vậy. Lưu ý dùng excel phiên bản tầng thứ 9 cửu âm chân kinh 365 mới được.
Cho trước 1 ngày cột mốc nào đó (ví dụ hôm nay), Cho trước số lần tìm Thứ Sáu ngày 13 (ví dụ 10 ngày),

Danh sách các ngày thứ sáu 13 trở về trước (trước ngày cột mốc):


Danh sách các ngày thứ sáu 13 trở về sau (sau ngày cột mốc):


Nối 2 danh sách bên trên lại thành 1 danh sách gom bỏ vô trong 1 cột (Kiểu như "append data"):


View attachment 265746
Vì bài này mảng là Date nên có thể dùng cách này để gom 2 mảng
Mã:
=LET(a,A4#,b,B4#,SMALL((a,b),SEQUENCE(COUNT(a,b))))

Nếu đã có 2 danh sách ở A4 và B4 thì nối lại như sau:

=LET(db,A4#,da,B4#,rwb,ROWS(db),rwa,ROWS(da),IF(SEQUENCE(rwb+rwa)<=rwb,INDEX(db,SEQUENCE(rwb+rwa),1),INDEX(da,SEQUENCE(rwb+rwa)-rwb,1)))
Nếu đặt thêm biến nữa công thức sẽ gọn, so index thì 2 mảng không cùng cấu trúc vẫn được vì nó luôn xét từ trên xuống
Mã:
=LET(db,A4#,da,B4#,lst,SEQUENCE(ROWS(db)+ROWS(db))-ROWS(db),IF(lst<=0,db,INDEX(da,lst)))


Góp vui dùng 365 cho bài này không tách khớp
Mã:
=LET(td,TODAY(),n,10,l_date,td+SEQUENCE(10001)-5001,l_filter,FILTER(l_date,TEXT(l_date,"dd ddd")="13 Fri"),pst,MATCH(td,l_filter),INDEX(l_filter,SEQUENCE(n*2)-n+pst))
 
Lần chỉnh sửa cuối:
Góp vui dùng 365 cho bài này không tách khớp
Mã:
=LET(td,TODAY(),n,10,l_date,td+SEQUENCE(10001)-5001,l_filter,FILTER(l_date,TEXT(l_date,"dd ddd")="13 Fri"),pst,MATCH(td,l_filter),INDEX(l_filter,SEQUENCE(n*2)-n+pst))
Khà khà khà, đúng là ngọa hổ tàng long. Mong anh em bằng hữu có dịp đàm đạo luận kiếm, cầm tay uống rượu!
 
Thấy mấy bạn dùng hàm tôi hoảng hồn.
 
Một công thức thôi, nhập vào ô bất kỳ (chỉ dùng Excel 2007 hoặc 2010)
Mã:
=IF(ROWS(A$1:A1)<11,AGGREGATE(14,6,(EDATE(EDATE(TODAY()-DAY(TODAY())+13,-(DAY(TODAY())<=13)),1-ROW($1:$120)))/
(WEEKDAY(EDATE(EDATE(TODAY()-DAY(TODAY())+13,-(DAY(TODAY())<=13)),1-ROW($1:$120)))=6),11-ROWS(A$1:A1)),
IF(ROWS(A$1:A1)<21,AGGREGATE(15,6,(EDATE(EDATE(TODAY()-DAY(TODAY())+13,--(DAY(TODAY())>13)),ROW($1:$120)-1))/(WEEKDAY(EDATE(EDATE(TODAY()-DAY(TODAY())+13,--(DAY(TODAY())>13)),ROW($1:$120)-1))=6),ROWS(A$1:A1)-10),""))
Kết thúc bình thường Enter.

Kéo xuống dưới thành 20 dòng.

10 dòng đầu là 10 ngày trước, 10 dòng sau là 10 ngày sau. 20 ngày theo đúng thứ tự tăng dần từ quá khứ tới tương lai.

Công thức có 2 nhánh (2 IF) để tính 10 trước và 10 ngày sau. Nếu muốn tính 10 ngày trước và 10 ngày sau riêng rẽ ở 2 cột thì "cắt" từ công thức ở trên ra.
 
Mình không biết dùng hàm mình ngồi mình đếm thủ công tầm 10 năm từ 1/1/2021 đến 31/12/2031 thì có 17 ngày thứ sáu ngày 13:

1631273379214.png
Bài đã được tự động gộp:

Cách của bạn chỉ tìm 1 trong mười ngày đó mà thôi;
Đề bài là tìm cả mười ngày thứ sáu 13 gần nhất trong 1 lúc cơ!

Mình thử viết hàm mảng tự tạo & có nội dung sau:
PHP:
Function T6N13(Optional Dat As Date)
 ReDim Arr(1 To 10, 1 To 3)
 Dim J As Long, W As Integer
 
 If Dat < 9 Then Dat = Date
 If Day(Dat) = 13 Then Dat = Dat - 1
 For J = 1 To 10000
 If Day(J + Dat) = 13 And Weekday(J + Dat) = 6 Then
    W = W + 1:                  Arr(W, 2) = Format(J + Dat, "MM/DD/yy")
    Arr(W, 3) = J:              Arr(W, 1) = W
 End If
 If W = 10 Then Exit For
 If Day(Dat - J) = 13 And Weekday(Dat - J) = 6 Then
    W = W + 1:                  Arr(W, 2) = Format(Dat - J, "MM/DD/yy")
    Arr(W, 3) = Space(1) & -J:  Arr(W, 1) = W
 End If
 If W = 10 Then Exit For
 Next J
 T6N13 = Arr()
End Function
Mình viết code thấy nó ngắn gọn sao các bác viết dài thòn vậy ta?

PHP:
Sub Test()
    Dim arrDate()
    Dim n As Long
    Dim d As Date, dteFromDate As Date, dteToDate As Date
    dteFromDate = Date
    dteToDate = DateSerial(2031, 12, 31)
    For d = dteFromDate To dteToDate
        If Weekday(d) = 6 And Day(d) = 13 Then
            n = n + 1
            ReDim Preserve arrDate(1 To n)
            arrDate(n) = d
            If n = 10 Then Exit For
        End If
    Next
    Range("F5").Resize(n).Value = WorksheetFunction.Transpose(arrDate)
End Sub
 
Lần chỉnh sửa cuối:
Mình không biết dùng hàm mình ngồi mình đếm thủ công tầm 10 năm từ 1/1/2021 đến 31/12/2031 thì có 17 ngày thứ sáu ngày 13:

View attachment 265791
Có năm có 1, có năm có 2, 3 thứ 6 ngày 13. Trong công thức ở bài #35 tôi lấy trung bìng là 1 năm 1 lần thứ 6 ngày 13. Vì thế để xét 10 lần thứ 6 ngày 13 thì tôi xét 10 năm, tức 120 tháng. Vì thế có con số 120 - ROW($1:$120)
 
Mình viết code thấy nó ngắn gọn sao các bác viết dài thòn vậy ta?

PHP:
Sub Test()
    Dim arrDate()
    Dim n As Long
    Dim d As Date, dteFromDate As Date, dteToDate As Date
    dteFromDate = Date
    dteToDate = DateSerial(2031, 12, 31)
    For d = dteFromDate To dteToDate
        If Weekday(d) = 6 And Day(d) = 13 Then
            n = n + 1
            ReDim Preserve arrDate(1 To n)
            arrDate(n) = d
            If n = 10 Then Exit For
        End If
    Next
    Range("F5").Resize(n).Value = WorksheetFunction.Transpose(arrDate)
End Sub
Từ hiện tại phải dò theo 2 hướng chứ bạn?
 
Từ hiện tại phải dò theo 2 hướng chứ bạn?
Hướng nào và hướng nào?

Còn dùng hàm còn ngắn gọn hơn nữa!
PHP:
Function FindFriday13th(ByVal intCount As Integer) As Variant
    Dim arrDate(), d As Date, n As Long
    d = Date
    Do
        If Weekday(d) = 6 And Day(d) = 13 Then
            n = n + 1
            ReDim Preserve arrDate(1 To n)
            arrDate(n) = d
            If n = intCount Then Exit Do
        End If
        d = d + 1
    Loop
    FindFriday13th = WorksheetFunction.Transpose(arrDate)
End Function

Nếu như trong bài đếm số lượng 10 ngày gần đây nhất thì công thức: =FindFriday13th(10)
 
Hướng nào và hướng nào?

Còn dùng hàm còn ngắn gọn hơn nữa!
PHP:
Function FindFriday13th(ByVal intCount As Integer) As Variant
    Dim arrDate(), d As Date, n As Long
    d = Date
    Do
        If Weekday(d) = 6 And Day(d) = 13 Then
            n = n + 1
            ReDim Preserve arrDate(1 To n)
            arrDate(n) = d
            If n = intCount Then Exit Do
        End If
        d = d + 1
    Loop
    FindFriday13th = WorksheetFunction.Transpose(arrDate)
End Function

Nếu như trong bài đếm số lượng 10 ngày gần đây nhất thì công thức: =FindFriday13th(10)
Thì chủ thớt đã nói rồi đó chi. Gần nhất 10 ngày là phải tính 5 ngày từ hiện tại đến tương lai + 5 ngày từ hiện tại đến quá khứ.
 
Web KT
Back
Top Bottom