Chú ý: Các thành viên học lớp "Lập trình VBA trong Excel" có thể trao đổi bài ở đây

Liên hệ QC
Nếu 1 tham số fức tạp thì ta tách ra làm 2 cái đơn giản, như đang dởn vậy mà

Các bạn trong lớp thử xem sao nha:

MySumIf (Rng2Cot As Range, dNum As Double, sType As String)

Ta quy ước với hàm fải hiểu các tham số nhập vô như sau:

sType | Fải hiểu
"B"| "="
"NB"|"<="
"LB"|">="
"L"|">"
"N"|"<"


Khà, khà, . . . . . vụng chèo khéo chống í mà!
 
Lần chỉnh sửa cuối:
Các bạn trong lớp thử xem sao nha:

MySumIf (Rng2Cot As Range, dNum As Double, sType As String)

Ta quy ước với hàm fải hiểu các tham số nhập vô như sau:

sType | Fải hiểu
"B"| "="
"NB"|"<="
"LB"|">="
"L"|">"
"N"|"<"

Khà, khà, . . . . . vụng chèo khéo chống í mà!
Em làm theo ý bác ạ


PHP:
Function MySumIf(ByVal rngValue As Range, ByVal lTest As Long, ByVal sType As String) As Long
    Dim i As Long, j As Long
    For i = 1 To rngValue.Rows.Count
        For j = 1 To rngValue.Columns.Count
            Select Case sType
                Case "k","K"
                    If rngValue(i, j) <> lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "B", "b"
                    If rngValue(i, j) = lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NB", "Nb", "nb", "nB"
                    If rngValue(i, j) <= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NH", "Nh", "nh", "nH"
                    If rngValue(i, j) < lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LB", "Lb", "lb", "lB"
                    If rngValue(i, j) >= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LH", "Lh", "lh", "lH"
                    If rngValue(i, j) > lTest Then MySumIf = MySumIf + rngValue(i, j)
            End Select
        Next
    Next
End Function
 

File đính kèm

  • MySumIf.rar
    12.5 KB · Đọc: 7
Lần chỉnh sửa cuối:
Các bạn trong lớp thử xem sao nha:

MySumIf (Rng2Cot As Range, dNum As Double, sType As String)

Ta quy ước với hàm fải hiểu các tham số nhập vô như sau:

sType | Fải hiểu
"B"| "="
"NB"|"<="
"LB"|">="
"L"|">"
"N"|"<"


Khà, khà, . . . . . vụng chèo khéo chống í mà!
Chả hiểu hàm countif(....,">=100") trong excel nó dịch phần ">=100" ra làm sao.
Nếu dùng replace hay instr thì có vẻ rừng quá. Mà dùng "L" hay "LB" em thấy còn rừng hơn. Hay dùng Cvar(...) chả biết có OK.
Các bác giúp em giải thuật tách ">=100" ra.
Cám ơn các bác.
Em dùng thử code sau để test không biết có đúng không. Các bác xem giúp em.
PHP:
Function Kiemtra(Rng As Range, sStr As String) As Boolean
  Kiemtra = Evaluate(Rng & sStr)
End Function
Cú pháp
=KiemTra(A1,">=1000")
Nếu A1 >= 1000 thì true.
 
Lần chỉnh sửa cuối:
Thay vì Case "NB", "Nb", "nb", "nB" ta có thể dùng Select Case Ucase(sType) chứ nhỉ?

Bác Sa chắc lụt nghề, hoặc là đang thử anh em. Dùng B, LB, L, NB, N, còn thiếu 1 ký hiệu K = "<>". Mà đã tách ta 2 tham số thì để nguyên >, <, >=, <=, <> cho khoẻ. Select Case khỏi B, b, khỏi NB, nb, Nb, nB, lung tung xà bần. Dùng Evaluate như ThuNghi có thể không cần tách ra 2 tham số.
 
Thay vì Case "NB", "Nb", "nb", "nB" ta có thể dùng Select Case Ucase(sType) chứ nhỉ?

Bác Sa chắc lụt nghề, hoặc là đang thử anh em. Dùng B, LB, L, NB, N, còn thiếu 1 ký hiệu K = "<>". Mà đã tách ta 2 tham số thì để nguyên >, <, >=, <=, <> cho khoẻ. Select Case khỏi B, b, khỏi NB, nb, Nb, nB, lung tung xà bần. Dùng Evaluate như ThuNghi có thể không cần tách ra 2 tham số.

Các bác làm em loạn hết cả rồi, bài trên em làm là tất cả kiến thức bọn em mới học, còn kiến thức khác thì bọn em chịu không biết gì luôn.
 
Tôi nói trong trình độ của lớp ấy chứ. Thí dụ sau không cần xét mọi trường hợp như nb, NB, Nb, nB, dùng nguyên code của hungtttv, có bổ sung ký hiệu K = <>:
PHP:
Function MySumIf(ByVal rngValue As Range, ByVal lTest As Long, ByVal sType As String) As Long
    Dim i As Long, j As Long
    For i = 1 To rngValue.Rows.Count
        For j = 1 To rngValue.Columns.Count
            Select Case UCase(sType)
                Case "B"
                    If rngValue(i, j) = lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NB"
                    If rngValue(i, j) <= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NH"
                    If rngValue(i, j) < lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LB"
                    If rngValue(i, j) >= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LH"
                    If rngValue(i, j) > lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "K"
                    If rngValue(i, j) <> lTest Then MySumIf = MySumIf + rngValue(i, j)
            End Select
        Next
    Next
End Function

Còn nếu để nguyên các ký hiệu như cũ, sẽ dễ dành cho người dùng hơn, (nguyên tắc viết code là viết hàm thuận tiện cho người dùng, chứ không phải viết hàm thuận tiện cho người viết).

PHP:
Function MySumIf(ByVal rngValue As Range, ByVal lTest As Long, ByVal sType As String) As Long
    Dim i As Long, j As Long
    For i = 1 To rngValue.Rows.Count
        For j = 1 To rngValue.Columns.Count
            Select Case sType
                Case "="

                Case "<="
 
                Case "<"

                Case ">="

                Case ">"

                Case "<>"
            End Select
        Next
    Next
End Function
 
Các thầy có bài nào phù hợp với những kiến thức bọn em đã học thì các thầy đưa lên đây để bọn em làm nhé. Em nghĩ trong các kiến thức bọn em học trên lớp đã có rất nhiều vấn đề mà bọn em chưa va phải, mà chỉ có cách là làm bài tập nhiều mới thấy được thôi. EM cám ơn trước ạ!!!
 
Ủa sao kỳ vậy ta! SUMIF mà sao chỉ có Vùng điều kiện, còn vùng tính tổng ở đâu?
Lý ra thì hàm này phải có 3 tham số ---> MySumIf(SourceRange as Range, Criteria, SumRange as Range)
Nếu bỏ qua SumRange thì sẽ gán SumRange = SourceRange
---------------
Nghiên cứu cũng để chơi thôi chứ muốn bắt chước y chang như SUMIF của bác Bill thật chẳng dễ nhai đâu!
 
Ủa sao kỳ vậy ta! SUMIF mà sao chỉ có Vùng điều kiện, còn vùng tính tổng ở đâu?
Lý ra thì hàm này phải có 3 tham số ---> MySumIf(SourceRange as Range, Criteria, SumRange as Range)
Nếu bỏ qua SumRange thì sẽ gán SumRange = SourceRange
---------------
Nghiên cứu cũng để chơi thôi chứ muốn bắt chước y chang như SUMIF của bác Bill thật chẳng dễ nhai đâu!

Em thấy SumRange không có cũng được mà bác. Trong hàm Sumif không có cũng được mà
Đây là làm theo yêu cầu của Khanhhoan thôi

Em muốn hỏi nếu làm hàm MySumIf hay MyCountIf mà điều kiện không phải là một giá trị mà là một khoảng, như tìm tổng của tất cả những số trong vùng có giá trị lớn hơn (hay nhỏ hơn) một số cụ thể thì làm thế nào?
Ví dụ như hàm sẵn có trong excel thì ta có thể viết =SumIf(A1:B5,">10")
 
Em thấy SumRange không có cũng được mà bác. Trong hàm Sumif không có cũng được mà
Đây là làm theo yêu cầu của Khanhhoan thôi
Không có cũng được có nghĩa là khi dùng bạn có thể bỏ qua tùy theo yêu cầu... Còn khi viết hàm thì phải đủ chứ ---> Có phải lúc nào vùng tính tồng và vùng điều kiện cũng là một đâu nè
-------------
Vẫn còn chưa nói đến cái vụ KÝ TỰ ĐẠI DIỆN * ? nữa đấy nha
 
Lần chỉnh sửa cuối:
Các thầy có bài nào phù hợp với những kiến thức bọn em đã học thì các thầy đưa lên đây để bọn em làm nhé. Em nghĩ trong các kiến thức bọn em học trên lớp đã có rất nhiều vấn đề mà bọn em chưa va phải, mà chỉ có cách là làm bài tập nhiều mới thấy được thôi. EM cám ơn trước ạ!!!
Có bài này là lấy trên GPE từ TransferData của NDU đã làm, các bạn viết cho 1 hàm Max và Min Price theo 2 điều kiện là Company Name và Services. Tuỳ chọn tại F2 và G2 của file.
Tôi mới làm ct mà ct mảng nên chậm quá, các bạn giúp tôi làm 1 UDF nhé.
Hy vọng bài loại này có nhiều áp dụng thực tế.
Cám ơn các bạn nhiều.
 

File đính kèm

  • MinMaxIf.rar
    10.5 KB · Đọc: 10
Không có cũng được có nghĩa là khi dùng bạn có thể bỏ qua tùy theo yêu cầu... Còn khi viết hàm thì phải đủ chứ ---> Có phải lúc nào vùng tính tồng và vùng điều kiện cũng là một đâu nè
Em chỉ lấy ví dụ đơn giản như cho 1 vùng số và tính tổng của tất cả những số trong vùng mà lớn hơn 1 giá trị a nào đó, hàm sumif của excel cũng làm được điều này mà chỉ cần vùng chứa số liệu và điều kiện ">a". Chỉ là chức năng giống nhau thôi chứ em không nói là viết 1 hàm giống hệt SUMIF.
 
Lần chỉnh sửa cuối:
Tôi mới làm ct mà ct mảng nên chậm quá, các bạn giúp tôi làm 1 UDF nhé.
Hy vọng bài loại này có nhiều áp dụng thực tế.
Cám ơn các bạn nhiều.
Chẳng lý nào với bài này mà ThuNghi lại NHỜ GIÚP ---> Chắc đưa bài lên cho các bạn khác làm bài tập đây?
------------------------
Em chỉ lấy ví dụ đơn giản như cho 1 vùng số và tính tổng của tất cả những số trong vùng mà lớn hơn 1 giá trị a nào đó, hàm sumif của excel cũng làm được điều này mà chỉ cần vùng chứa số liệu và điều kiện ">a". Chỉ là chức năng giống nhau thôi chứ em không nói là viết 1 hàm giống hệt SUMIF.
Đồng ý rằng ta "hạ độ khó" của bài toán cho các bạn dễ nghiên cứu, tìm hiểu... Nhưng nếu muốn tiến bộ, hãy nghĩ đến hướng "nâng cao" NGAY TỪ BÂY GIỜ đi
 
Xin phép các bác cho em khởi động bài tập về nhà ngày hôm qua. Thầy cho 2 bài, đây là bài 1:
Đề bài: Viết thủ tục tìm dòng cuối cùng của 1 vùng nào đó
Đây là bài làm của em (Mặc dù em biết có cách sử dụng .End(xlUp) cũng có thể xác định được dòng cuối cùng, nhưng em đang làm theo nhưng vòng lặp đã học (Do While, For) để xác định, có thể bài hơi dài, mong các bác góp ý.

Mã:
Sub LastCell()
    Dim rngNum As Range
    Dim i As Integer
    Dim j As Integer
    Dim x As Integer
        
    Set rngNum = Selection
    i = rngNum.Rows.Count
    x = 1
    Do While i <> 0
    For j = 1 To rngNum.Columns.Count
        If IsEmpty(rngNum.Cells(i, j)) = False Then
        userrespond = MsgBox("Dong cuoi cung la " & rngNum.Cells(i, j).Row, vbOKOnly, "Thong bao!")
        x = 0
        Exit Do
        End If
    Next
    i = i - 1
    Loop
    If x = 1 Then
    userrespond = MsgBox("Vung du lieu toan dong trang", vbOKOnly, "Thong bao!")
    End If
End Sub

P/S: Bác Ngọc NH_DK có thể gửi PM kho vào hòm thư thangacc@gmail.com cho em nhé, có gì anh em cùng trao đổi. Cảm ơn bác
 
Lần chỉnh sửa cuối:
Đây là code BT1 nhé:
PHP:
Sub Tim_dong()
    Dim rngVung As Range, i As Long
    i = 1
        Do While i <= Range("A1:A65535").Count
            If Not IsEmpty(Range("A1:A65535").Item(i)) _
            Then Set rngVung = Range("A1:A65535").Item(i)
         i = i + 1
    Loop
    If rngVung Is Nothing Then
        MsgBox "Khong thay dong DL nao ca!"
    Else
        MsgBox "Dong DL cuoi cung la: " & rngVung.Address
    End If
    Set rngVung = Nothing
End Sub
 
Lần chỉnh sửa cuối:
Xin phép các bác cho em khởi động bài tập về nhà ngày hôm qua. Thầy cho 2 bài, đây là bài 1:
Đề bài: Viết thủ tục tìm dòng cuối cùng của 1 vùng nào đó
Đây là bài làm của em (Mặc dù em biết có cách sử dụng .End(xlUp) cũng có thể xác định được dòng cuối cùng, nhưng em đang làm theo nhưng vòng lặp đã học (Do While, For) để xác định, có thể bài hơi dài, mong các bác góp ý.

Mã:
Sub LastCell()
    Dim rngNum As Range
    Dim i As Integer
    Dim j As Integer
    Dim x As Integer
        
    Set rngNum = Selection
    i = rngNum.Rows.Count
    x = 1
    Do While i <> 0
    For j = 1 To rngNum.Columns.Count
        If IsEmpty(rngNum.Cells(i, j)) = False Then
        userrespond = MsgBox("Dong cuoi cung la " & rngNum.Cells(i, j).Row, vbOKOnly, "Thong bao!")
        x = 0
        Exit Do
        End If
    Next
    i = i - 1
    Loop
    If x = 1 Then
    userrespond = MsgBox("Vung du lieu toan dong trang", vbOKOnly, "Thong bao!")
    End If
End Sub
P/S: Bác Ngọc NH_DK có thể gửi PM kho vào hòm thư thangacc@gmail.com cho em nhé, có gì anh em cùng trao đổi. Cảm ơn bác
Đã gọi là CÓ DỮ LIỆU thì phải tính luôn Comment nữa nha
Ngoài ra, nếu dùng vòng lập, nên quét từ dưới lên, theo nguyên tắc:
- Cho trước biến MaxRow = 0
- Quét từng cột
- Quét từng dòng, từ dưới lên, nếu Cell không rổng hoặc có Comment thì xét tiếp:
* Nếu MaxRow < Vị trí dòng đang xét thì gán MaxRow = Vị trí dòng ấy
- Thoát vòng lập, chuyển sang cột khác
--------
Ví dụ là thế này:
PHP:
Sub xLastCell()
  Dim sRng As Range, i As Long, j As Long, MaxR As Long, Answer As String
  Set sRng = Selection
  For j = 1 To sRng.Columns.Count
    For i = sRng.Rows.Count To 1 Step -1
      If Not IsEmpty(sRng(i, j)) Or Not sRng(i, j).Comment Is Nothing Then
        If MaxR < sRng(i, j).Row Then MaxR = sRng(i, j).Row
        Exit For
      End If
    Next
  Next
  Answer = IIf(MaxR, "Dong cuoi cùng la " & MaxR, "Vùng du liêu toàn dòng trang")
  MsgBox Answer, 6, "Thông báo"
End Sub
 
Lần chỉnh sửa cuối:
Em sửa lại chút xíu cho rộng hơn nè............
PHP:
Sub Tim_dong()
    Dim rngVung As Range, i As Long
    i = 1
        Do While i <= Selection.Count
            If Not IsEmpty(Selection.Item(i)) _
            Then Set rngVung = Selection.Item(i)
         i = i + 1
    Loop
    If rngVung Is Nothing Then
        MsgBox "Khong thay dong DL nao ca!"
    Else
        MsgBox "Dong DL cuoi cung la: " & rngVung.Address
    End If
    Set rngVung = Nothing
End Sub
 
Cảm ơn thầy, em không để ý tới ô chứ comment trong vùng. Code của thầy rõ ràng và ngắn gọn hơn hẳn.
Thực ra vòng Do While của em cũng xét từ dưới lên trên, và khi đã xét từ dưới lên trên thì khi nào có dữ liệu thì dòng đó sẽ là dòng cuối (max), theo em nghĩ không cần thiết phải gán thêm 1 biến MaxRow vào, có thể xác định luôn nó
Ý em là dòng
If MaxR < sRng(i, j).Row Then MaxR = sRng(i, j).Row
có thể sửa thành
Và theo em sau khi đã có giá trị MaxR, ca 2 vòng lặp không cần chạy nữa, vì vậy nên tách ra Do ... While bên ngoài vong For để mình dùng Exit Do, nó sẽ thoát luôn. Nếu không sau khi Exit For vòng lặp vẫn chạy thêm các giá trị của j còn lại --> sẽ bị lâu
 
Cảm ơn thầy, em không để ý tới ô chứ comment trong vùng. Code của thầy rõ ràng và ngắn gọn hơn hẳn.
Thực ra vòng Do While của em cũng xét từ dưới lên trên, và khi đã xét từ dưới lên trên thì khi nào có dữ liệu thì dòng đó sẽ là dòng cuối (max), theo em nghĩ không cần thiết phải gán thêm 1 biến MaxRow vào, có thể xác định luôn nó
Ý em là dòng có thể sửa thành Và theo em sau khi đã có giá trị MaxR, ca 2 vòng lặp không cần chạy nữa, vì vậy nên tách ra Do ... While bên ngoài vong For để mình dùng Exit Do, nó sẽ thoát luôn. Nếu không sau khi Exit For vòng lặp vẫn chạy thêm các giá trị của i còn lại --> sẽ bị lâu
Đâu có được ---> Selection của ta là nhiều dòng nhiều cột! MaxRow của cột này chắc gì đã là MaxRow của cột khác
Nếu bạn thay If MaxR < sRng(i, j).Row Then MaxR = sRng(i, j).Row thành MaxR = sRng(i, j).Row thì nó sẽ lấy MaxRow ở cột cuối cùng (dù dòng cuối của cột này chưa chắc có giá trị lớn nhất)
Không tin bạn có thể thí nghiệm để kiểm chứng điều này vào code của tôi
--------------------------------
Còn cách của bạn có hơi khác... vì bạn quét theo cột trước, từ cột 1 của dòng cuối đến cột cuối của dòng cuối rồi từ đó đi lên, nếu thấy cell <> rổng thì Exit Do
Tôi thì quét theo dòng trước, từ dòng cuối cột 1 trờ lên, xong mới chuyển qua cột khác
Xét về tốc độ có lẽ bạn đã đúng ---> Vậy cứ chuyển đổi 2 vòng lập for này cho nhau là được rồi (Do hay For gì cũng được cả)
 
Lần chỉnh sửa cuối:
Vâng đúng ạ, em test bỏ if đi thì có vùng đúng, có vùng nó chọn sai dòng
 
Web KT
Back
Top Bottom