Thảo luận về hàm MAX tự tạo (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,662
Được thích
16,725
Giới tính
Nam
Tách

VBA - để hình dung được thuật toán là khó nhất, cách học thuật toán của mình đó là tưởng tượng mình làm bằng tay như thế nào thì mô tả lại như thế, ví dụ thế này :
PHP:
Sub timMax()
Dim i As Long, maxV As Long
Dim Rng As Range
Set Rng = Range("A2:A14")
maxV = Cells(2, 1).Value
    For i = 3 To 14
        If Cells(i, 1).Value > maxV Then maxV = Cells(i, 1).Value
    Next
MsgBox maxV
End Sub
Có phải làm bằng tay thì thế này không?
Đầu tiên sẽ nhìn dòng đầu tiên của vùng dữ liệu đó coi giá trị đó là lớn nhất- ghi giá trị đó vào giấy nháp, sau đó đi dò các dòng tiếp theo sau, cứ em nào lớn hơn thì ghi tiếp nó ra giấy nháp, cứ như thế dò cho đến hết vùng dữ liệu đó ta sẽ được giá trị cuối cùng chính là giá trị max.
Mình làm đúng như thế đó. Thực ra theo mình mới học VBA thì làm những ví dụ đơn giản mà ngắn ngắn thôi, chứ dài ngoằng chỉ mỗi việc ngồi theo dõi thuật toán thôi cũng đủ KHÓC rồi.

Hình như bạn hỏi bài, cần được giúp đỡ, hướng dẫn hơn là bạn đưa ra một bài tập mà bạn đã có sẳn đáp án.

Thôi thì tôi giúp cho bạn luôn đây!

Với cách làm trên của bạn, kể cả của tôi không thể ra được số lớn nhất nếu nó âm đâu, bởi lúc đầu tôi chỉ đưa thuật toán lên vì tôi nghĩ bạn đã có lời giải rồi.

Chúng ta bắt đầu suy luận nhé!

Nói đến hàm Max thì cho dù nó là số nguyên hay nó là số thực ta phải thừa nhận. Tôi nghĩ số cần tìm thuộc kiểu dữ liệu DOUBLE (Double Type). Xét đến double thì ta phải xét đến số nhỏ nhất của nó, đó chính là: -1.79769313486231E+308

Từ đây ta đã dễ dàng lắp ghép vào thủ tục:

PHP:
Sub RangeMax()
      Dim n As Double, cel As Range, m As Long
      n = -1.79769313486231E+308
      For Each cel In Sheet1.Range("A2:A14")
            If cel <> "" And IsNumeric(cel) Then
                  m = m + 1
                  If cel >= n Then n = cel
            End If
      Next
      If m Then MsgBox n
End Sub


Và như thế, ta phát triển nó thành hàm tự tạo như sau:

PHP:
Function udfMax(ByVal MyRange As Variant) As Double
      Dim sArray As Variant, itm As Variant, n As Double, m As Long
      n = -1.79769313486231E+308
      sArray = MyRange
      For Each itm In sArray
            If itm <> "" And IsNumeric(itm) Then
                  m = m + 1
                  If itm >= n Then n = itm
            End If
      Next
      If m Then udfMax = n
End Function

Bạn không còn gì thắc mắc nữa chứ!?

Chúc các bạn ngày càng tiến bộ!
 
Lần chỉnh sửa cuối:
Nếu không dùng đến con số 1.79769313486231E+308 thì có xây dựng hàm được không ta?
Ẹc... Ẹc... tôi nghĩ là vẫn.. được như thường

Vậy Thầy làm thử và em sẽ thử lại với hàm MAX của Excel ạ. Em rất mong được học hỏi từ Thầy.
 
Upvote 0
Vậy Thầy làm thử và em sẽ thử lại với hàm MAX của Excel ạ. Em rất mong được học hỏi từ Thầy.

Viết đại nó thế này xem:
PHP:
Function udfMax(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    For Each Item In tmpArr
      If TypeName(Item) <> "Error" Then
        tmp = CDbl(Item)
        n = n + 1
        If n = 1 Or dMax < tmp Then dMax = tmp
      End If
    Next
  Next
  udfMax = dMax
End Function
Nghĩa test thử xem
 
Lần chỉnh sửa cuối:
Upvote 0
Viết đại nó thế này xem:
PHP:
Function udfMax(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    For Each Item In tmpArr
      If TypeName(Item) <> "Error" Then
        tmp = CDbl(Item)
        n = n + 1
        If n = 1 Or dMax < tmp Then dMax = tmp
      End If
    Next
  Next
  udfMax = dMax
End Function
Nghĩa test thử xem

Dạ, em đã test thử giữa hàm MAX và hàm Thầy vừa gửi lên, kể cả hàm của em cũng được test chung với cùng một con số: -7.9769313486231E+307

Kết quả đạt được ở Hàm của Thầy bằng 0 và những hàm còn lại đều cho ra chính số đó ạ.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Dạ, em đã test thử giữa hàm MAX và hàm Thầy vừa gửi lên, kể cả hàm của em cũng được test chung với cùng một con số: -7.9769313486231E+307

Kết quả đạt được ở Hàm của Thầy bằng 0 và những hàm còn lại đều cho ra chính số đó ạ.

Vì hàm tôi viết xem cell rổng =0
Muốn bỏ cell rổng thì sửa em này:
If TypeName(Item) <> "Error" Then
thành vầy:
If TypeName(Item) <> "Error" And TypeName(Item) <> "Empty" Then
--------------
Điều quan trọng không nằm ở chổ đó mà ở GIẢI THUẬT... Ngoài ra hàm này hoạt động trên mảng và range luôn nha
 
Upvote 0
Vì hàm tôi viết xem cell rổng =0
Muốn bỏ cell rổng thì sửa em này:
If TypeName(Item) <> "Error" Then
thành vầy:
If TypeName(Item) <> "Error" And TypeName(Item) <> "Empty" Then
--------------
Điều quan trọng không nằm ở chổ đó mà ở GIẢI THUẬT... Ngoài ra hàm này hoạt động trên mảng và range luôn nha
Em vừa cập nhật hàm mới nhất:

Mã:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    For Each Item In tmpArr
      [COLOR=#ff0000][B]If TypeName(Item) <> "Error" And TypeName(Item) <> "Empty" Then[/B][/COLOR]
            tmp = CDbl(Item)
        n = n + 1
        If n = 1 Or dMax < tmp Then dMax = tmp
      End If
    Next
  Next
  udfMax_NDU = dMax
End Function

Kết quả cũng không khả quan gì ạ!
Việc thêm ParamArray vào hàm chắc sẽ không khó nếu hàm cho ra kết quả đúng.

===============================

CHẮC CÓ LẼ NHỜ SMOD, MOD CHUYỂN CÁC ĐỀ TÀI NÀY VÀO MỘT BOX RIÊNG Ạ.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em vừa cập nhật hàm mới nhất:

=
Kết quả cũng không khả quan gì ạ!
Việc thêm ParamArray vào hàm chắc sẽ không khó nếu hàm cho ra kết quả đúng.

===============================

CHẮC CÓ LẼ NHỜ SMOD, MOD CHUYỂN CÁC ĐỀ TÀI NÀY VÀO MỘT BOX RIÊNG Ạ.

Nếu muốn xài thì tự sửa đi đồng chí à! Mấy trò lẻ tẻ này đâu phải là khó đến mức suy nghĩ không ra
Ẹc... Ẹc...
 
Upvote 0
Nếu muốn xài thì tự sửa đi đồng chí à! Mấy trò lẻ tẻ này đâu phải là khó đến mức suy nghĩ không ra
Ẹc... Ẹc...

Nhưng Thầy kiểm tra lại Hàm Thầy gửi lên đi ạ! Nó chưa có đúng mà!

Em vừa cập nhật hàm mới nhất:

Mã:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    For Each Item In tmpArr
      [COLOR=#ff0000][B]If TypeName(Item) <> "Error" And TypeName(Item) <> "Empty" Then[/B][/COLOR]
            tmp = CDbl(Item)
        n = n + 1
        If n = 1 Or dMax < tmp Then dMax = tmp
      End If
    Next
  Next
  udfMax_NDU = dMax
End Function

Kết quả cũng không khả quan gì ạ!
Việc thêm ParamArray vào hàm chắc sẽ không khó nếu hàm cho ra kết quả đúng.

===============================

CHẮC CÓ LẼ NHỜ SMOD, MOD CHUYỂN CÁC ĐỀ TÀI NÀY VÀO MỘT BOX RIÊNG Ạ.


Xin được tự dời bài để tránh làm loãng topic "Những bài tập đơn giản dành cho những người mới bắt đầu"
 

File đính kèm

Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Xin được tự dời bài để tránh làm loãng topic "Những bài tập đơn giản dành cho những người mới bắt đầu"

Sửa thành vầy xem:
If TypeName(Item) = "Double" Then
Trong hàm của Nghĩa có câu
If itm <> "" And IsNumeric(itm) Then
E rằng hơi chủ quan nha ---> Thử gõ chữ FALSE vào cell A8 xem sao
 
Upvote 0
Em chỉnh sửa theo chiều hướng chọn nhiều vùng, rất đơn giản:

PHP:
Function udfMax_HTN(ParamArray MyRange()) As Double
      Dim sArray As Variant, itm As Variant, n As Double, m As Long
      n = -1.79769313486231E+308
      For Each sArray In MyRange
            For Each itm In sArray
                  If itm <> "" And IsNumeric(itm) Then
                        m = m + 1
                        If itm >= n Then n = itm
                  End If
            Next
      Next
      If m Then udfMax_HTN = n
End Function

Và cái ParamArray này em đã học được từ Thầy ndu96081631
 
Upvote 0
Sửa thành vầy xem:
If TypeName(Item) = "Double" Then
Trong hàm của Nghĩa có câu
If itm <> "" And IsNumeric(itm) Then
E rằng hơi chủ quan nha ---> Thử gõ chữ FALSE vào cell A8 xem sao

Nghĩ cũng rất lạ nha Thầy, với hàm MAX "xịn" nếu ta đặt FALSE/ TRUE trong RANGE thì nó bỏ qua, nhưng nếu ta viết thế này: =MAX(A1:A10,FALSE) thì nó so sánh đấy!
 
Upvote 0
Với hàm MAX trong Excel, ngoài việc tham chiếu theo vùng nó còn tham chiếu từng mục đơn lẽ trong đó nữa.

VD: =MAX(1,4,5,2,-1) ---> 5

Vì thế, phải làm thêm 1 số việc cho hàm của mình nữa!

PHP:
Function udfMax_HTN(ParamArray MyRange()) As Double
      Dim sArray As Variant, Itm As Variant
      Dim i As Double, j As Double, n As Double, m As Double
      n = -1.79769313486231E+308: i = n
      For Each sArray In MyRange
            If IsArray(sArray) Then
                  For Each Itm In sArray
                        If Itm = "" Or Not IsNumeric(Itm) _
                        Or (Itm = 0 And Len(Itm) > 1) _
                        Or (Itm = -1 And Len(Itm) > 2) Then _
                        GoTo NextItm
                              
                        m = m + 1
                        If Itm > n Then n = Itm
NextItm:
                  Next
            Else
                  If IsNumeric(sArray) Then
                        If TypeName(sArray) = "Boolean" Then
                              GoTo sBoolean
                        End If
                        
                        If sArray = "" Or Not IsNumeric(sArray) _
                        Or (sArray = 0 And Len(sArray) > 2) _
                        Or (sArray = -1 And Len(sArray) > 2) Then _
                        GoTo NextsArray
sBoolean:
                        
                        j = j + 1
                        If sArray = True And Len(sArray) > 2 Then sArray = 1
                        If sArray = False And Len(sArray) > 2 Then sArray = 0
                        
                        If sArray > i Then i = sArray
                  End If
            End If
NextsArray:
      Next
      If m Or j Then udfMax_HTN = IIf(n > i, n, i)
End Function

Bây giờ thì

=udfMax_HTN(A1:A10,TRUE,FALSE,1,3,7,-1,5)

Đều cho kết quả mỹ mãn!
 
Lần chỉnh sửa cuối:
Upvote 0
Hình như bạn hỏi bài, cần được giúp đỡ, hướng dẫn hơn là bạn đưa ra một bài tập mà bạn đã có sẳn đáp án.

Thôi thì tôi giúp cho bạn luôn đây!

Với cách làm trên của bạn, kể cả của tôi không thể ra được số lớn nhất nếu nó âm đâu,

Nghĩa thử chưa???

Hàm này của manuchungtinh chắc chắn là chuẩn tắc và ra được số lớn nhất dù là dãy số âm
PHP:
Sub timMax()
Dim i As Long, maxV As Long
Dim Rng As Range
Set Rng = Range("A2:A14")
maxV = Cells(2, 1).Value
    For i = 3 To 14
        If Cells(i, 1).Value > maxV Then maxV = Cells(i, 1).Value
    Next
MsgBox maxV
End Sub

Phải chú ý là vì đang học nên ở đây phải chú ý dãy số đó đầy đủ số liệu (không chứa cell rỗng -- điều này phù hợp với hàm sử dụng trong CODE nghĩa là sử dụng hàm max cho code của mình - chứ không phải liên quan cell gì cả)--còn bắt bẻ kiểu bạn thì còn nhiều trường hợp lắm - như bạn dẫn hàm max của excel ra đó.

Vấn đề là ở đây người học mới tiếp cận thì cần cái đơn giản - chính bạn đang không nghĩ đơn giản nên mới thành sa vào tranh luận
 
Lần chỉnh sửa cuối:
Upvote 0
Thôi thì vầy đi: Hai người, mỗi người cứ tự mình làm lấy 1 code về MAX, post lên đây "so cựa" nhau cho thực tế
Cải nhau cả mấy chục bài, thấy ngán quá, chả muốn vào xem luôn
(thuật toán cũng đơn giản, nhưng để làm giống như MAX của anh Bill cũng phải suy nghĩ hơi.. phê đấy nhé)
 
Lần chỉnh sửa cuối:
Upvote 0
Thôi thì vầy đi: Hai người, mỗi người cứ tự mình làm lấy 1 code về MAX, post lên đây "so cựa" nhau cho thực tế
Cải nhau cả mấy chục bài, thấy ngán quá, chả muốn vào xem luôn
(thuật toán cũng đơn giản, nhưng để làm giống như MAX của anh Bill cũng phải suy nghĩ hơi.. phê đấy nhé)

Đúng là như vậy, em muốn thuật toán của Thầy một cách, của em một cách và của ai đó một cách, hy vọng được học hỏi từ cách hay nhất, còn những bài mà Thầy cho là "cải nhau" chắc cũng nên cho vào sọt rác là đúng nhất.

Đây là học thuật chứ hàm MAX có sẳn thì viết làm gì nữa chứ!

Hàm của em tạm thời là như vậy, có thể sẽ chỉnh đốn thêm:

PHP:
Function udfMax_HTN(ParamArray MyRange()) As Double
      Dim sArray As Variant, Itm As Variant
      Dim i As Double, j As Double, n As Double, m As Double
      n = -1.79769313486231E+308: i = n
      For Each sArray In MyRange
            If IsArray(sArray) Then
                  For Each Itm In sArray
                        If Itm = "" Or Not IsNumeric(Itm) _
                        Or (Itm = 0 And Len(Itm) > 1) _
                        Or (Itm = -1 And Len(Itm) > 2) Then _
                        GoTo NextItm
                              
                        m = m + 1
                        If Itm > n Then n = Itm
NextItm:
                  Next
            Else
                  If IsNumeric(sArray) Then
                        If TypeName(sArray) = "Boolean" Then
                              GoTo sBoolean
                        End If
                        
                        If sArray = "" Or Not IsNumeric(sArray) _
                        Or (sArray = 0 And Len(sArray) > 2) _
                        Or (sArray = -1 And Len(sArray) > 2) Then _
                        GoTo NextsArray
sBoolean:
                        
                        j = j + 1
                        If sArray = True And Len(sArray) > 2 Then sArray = 1
                        If sArray = False And Len(sArray) > 2 Then sArray = 0
                        
                        If sArray > i Then i = sArray
                  End If
            End If
NextsArray:
      Next
      If m Or j Then udfMax_HTN = IIf(n > i, n, i)
End Function

Tôi nhớ không lầm thì ngày xưa Thầy AnhTuan1066 (ndu96081631), MrOkebap, Po_Pikachu, Huuthang_bd,..., và rất nhiều cao thủ khác tranh nhau từng phần ngàn giây về code của mình, thì tại sao chúng ta không dám thử sức với nhau như những thời hào hùng ngày xưa, nếu các bạn có thời gian, hãy đọc lại những bài ngày xưa của những cao thủ tôi vừa nói.
 
Lần chỉnh sửa cuối:
Upvote 0
Đúng là như vậy, em muốn thuật toán của Thầy một cách, của em một cách và của ai đó một cách, hy vọng được học hỏi từ cách hay nhất, còn những bài mà Thầy cho là "cải nhau" chắc cũng nên cho vào sọt rác là đúng nhất.

Đây là học thuật chứ hàm MAX có sẳn thì viết làm gì nữa chứ!

Hàm của em tạm thời là như vậy, có thể sẽ chỉnh đốn thêm:

PHP:
Function udfMax_HTN(ParamArray MyRange()) As Double
      Dim sArray As Variant, Itm As Variant
      Dim i As Double, j As Double, n As Double, m As Double
      n = -1.79769313486231E+308: i = n
    ................
  
NextsArray:
      Nex
      If m Or j Then udfMax_HTN = IIf(n > i, n, i)
End Function

Tôi nhớ không lầm thì ngày xưa Thầy AnhTuan1066 (ndu96081631), MrOkebap, Po_Pikachu, Huuthang_bd,..., và rất nhiều cao thủ khác tranh nhau từng phần ngàn giây về code của mình, thì tại sao chúng ta không dám thử sức với nhau như những thời hào hùng ngày xưa, nếu các bạn có thời gian, hãy đọc những bài của những cao thủ tôi vừa nói
Trời! Sao mà dài dử vậy ta? Không biết có "mưu đồ" gì trong này không nữa?
Tôi thì viết vầy:
PHP:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        If TypeName(Item) = "Double" Then
          tmp = CDbl(Item)
          n = n + 1
          If n = 1 Or dMax < tmp Then dMax = tmp
        End If
      Next
    Else
      If TypeName(tmpArr) = "Double" Then
        If dMax < tmpArr Then dMax = tmpArr
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Nghĩa test thử xem còn trường hợp nào chưa ổn ta sẽ bàn tiếp nhé
 
Upvote 0
Trời! Sao mà dài dử vậy ta? Không biết có "mưu đồ" gì trong này không nữa?
Tôi thì viết vầy:
PHP:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        If TypeName(Item) = "Double" Then
          tmp = CDbl(Item)
          n = n + 1
          If n = 1 Or dMax < tmp Then dMax = tmp
        End If
      Next
    Else
      If TypeName(tmpArr) = "Double" Then
        If dMax < tmpArr Then dMax = tmpArr
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Nghĩa test thử xem còn trường hợp nào chưa ổn ta sẽ bàn tiếp nhé

Xin Thầy hãy thử với =MAX(TRUE) và =udfMax_NDU(TRUE) mới thấy em đề ra là có lý.
 
Upvote 0
Xin Thầy hãy thử với =MAX(TRUE) và =udfMax_NDU(TRUE) mới thấy em đề ra là có lý.

Sửa tiếp:
Mã:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        [COLOR=#ff0000]If TypeName(Item) = "Boolean" Then tmp = -Item[/COLOR]
        If TypeName(Item) = "Double" Then
          tmp = CDbl(Item)
          n = n + 1
        End If
        If n = 1 Or dMax < tmp Then dMax = tmp
      Next
    Else
      [COLOR=#ff0000]If TypeName(tmpArr) = "Boolean" Then
        tmp = -tmpArr
        If dMax < tmp Then dMax = tmp
      End If[/COLOR]
      If TypeName(tmpArr) = "Double" Then
        If dMax < tmpArr Then dMax = tmpArr
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Càng lúc càng dài hen!
ẹc... ẹc...
 
Upvote 0
Sửa tiếp:
Mã:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        [COLOR=#ff0000]If TypeName(Item) = "Boolean" Then tmp = -Item[/COLOR]
        If TypeName(Item) = "Double" Then
          tmp = CDbl(Item)
          n = n + 1
        End If
        If n = 1 Or dMax < tmp Then dMax = tmp
      Next
    Else
      [COLOR=#ff0000]If TypeName(tmpArr) = "Boolean" Then
        tmp = -tmpArr
        If dMax < tmp Then dMax = tmp
      End If[/COLOR]
      If TypeName(tmpArr) = "Double" Then
        If dMax < tmpArr Then dMax = tmpArr
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Càng lúc càng dài hen!
ẹc... ẹc...
Chuẩn bị dài ra nữa nè thầy!

Bây giờ vùng dữ liệu chỉ có 1 chữ TRUE, và =MAX(A1:A10,FALSE) rồi hàm =udfMax_NDU(A1:A10,FALSE)
 
Upvote 0
Chuẩn bị dài ra nữa nè thầy!

Bây giờ vùng dữ liệu chỉ có 1 chữ TRUE, và =MAX(A1:A10,FALSE) rồi hàm =udfMax_NDU(A1:A10,FALSE)

Cái này thì tôi không đồng ý đâu nha!
Chúng ta có thể bắt chước MAX nhưng không nhất thiết bắt chước 100%... Vẫn có những chổ cải tiến theo kiểu khác
Nếu vùng A1:A10 chỉ có 1 chữ TRUE thì theo ý tôi =MAX(A1:A10,FALSE) phải cho kết quả = 1 mới hợp lý
Cũng giống như hàm MAX của Excel bị lỗi khi dữ liệu đầu vào bị lỗi nhưng hàm của tôi đã tránh được điều này (lỗi thì bỏ qua không tính)
 
Upvote 0
Cái này thì tôi không đồng ý đâu nha!
Chúng ta có thể bắt chước MAX nhưng không nhất thiết bắt chước 100%... Vẫn có những chổ cải tiến theo kiểu khác
Nếu vùng A1:A10 chỉ có 1 chữ TRUE thì theo ý tôi =MAX(A1:A10,FALSE) phải cho kết quả = 1 mới hợp lý
Cũng giống như hàm MAX của Excel bị lỗi khi dữ liệu đầu vào bị lỗi nhưng hàm của tôi đã tránh được điều này (lỗi thì bỏ qua không tính)

Theo ý kiến nhỏ của em, TRUE trong môi trường Excel và TRUE trong môi trường VBA là không bằng nhau, vì thế mới có vấn đề xảy ra như vậy. TRUE trong Excel = 1 còn TRUE trong VBA = -1, vì thế chính nội tại của nó mâu thuẫn với nhau như vậy nên nó bỏ qua khi gặp ô có giá trị TRUE. Và có lẽ điều này mà "anh BILL" cũng hợp bàn với "đàn em" dữ dội lắm để lấy giá trị nào, cuối cùng để "dĩ hòa di quý" thì "anh Bill" mới thống nhất lại rằng em TRUE nào ở trong cell thì bỏ qua, còn em TRUE nào nằm trong công thức thì tính là 1. Vì thế mới có chuyện lạ lùng là =MAX(A1) và A1 có giá trị là TRUE trong cell thì kết quả bằng 0 và công thức =MAX(TRUE) lại là 1.

Vấn đề thứ 2 (màu tím), em lại nghĩ tất cả các hàm, không riêng gì MAX thậm chí là toán tử +, - , *, / ... đều gặp ô bị lỗi sẽ "nhiễm bệnh" lỗi. Lỗi bị nhiễm ở mục đầu tiên nó gặp thì nó sẽ "nhiễm" lỗi tại đó.

Lý giải cho điều này, em lại suy luận. Chỉ nói riêng về hàm MAX, khi ta chọn tất cả các mục để tìm mục lớn nhất thì gặp ô bị lỗi, giả sử rằng ô đó là một hàm VLOOKUP tìm giá trị của 1 nhưng người tính lại quên vụ --, *1, ..., thì lỗi xảy ra là #N/A. Nếu giá trị của hàm hàm VLOOKUP đó đúng thì xảy ra 2 kết quả: hoặc số tìm được nhỏ hơn dãy số MAX đã tính hoặc là lớn hơn. Chính bản thân mình cũng không khẳng định được là giá trị nào lớn hơn vậy tại sao anh MAX lại bỏ qua được, nếu nhỏ hơn thì không nói gì, nếu lớn hơn thì sao? Vì thế tốt hơn hết, cứ thấy mục nào có lỗi đầu tiên thì ngưng tại đây không tính nữa vì giá trị không thể xác định được, đồng thời lấy lỗi đó làm lỗi của MAX luôn!

Chính vì THẦY đã nhắc ra điều "bỏ lỗi" này mà em lại học được một cách bẫy lỗi của các hàm trong Excel, tức bị lỗi gì thì hiện lên lỗi đó (#VALUE!, #N/A, #DIV/0!, #NAME?, #REF!, ...).

Hàm của em giờ đây đã được cải tiến như sau:

Mã:
Function udfMAX_HTN(ParamArray MyRange()) As Variant
      Dim sArray As Variant, Itm As Variant, ErrItm As Boolean
      Dim i As Double, j As Double, n As Double, m As Double
      n = -1.79769313486231E+308: i = n
      For Each sArray In MyRange
           [COLOR=#0000ff][B] If IsMissing(sArray) Then GoTo NextsArray[/B][/COLOR]
            If IsArray(sArray) Then
                  For Each Itm In sArray
                        [COLOR=#ff0000]If IsError(Itm) Then ErrItm = False: GoTo ErrorCase[/COLOR]
                        If Itm <> vbNullString Then
                              If Not IsNumeric(Itm) _
                                    Or (Itm = 0 And Len(Itm) > 2) _
                                    Or (Itm = -1 And Len(Itm) > 2) Then _
                                    GoTo NextItm
                              If Val(Itm) > n Then n = Val(Itm): m = 1
                        End If
NextItm:
                  Next
            Else
                  [COLOR=#ff0000]If IsError(sArray) Then ErrItm = True: GoTo ErrorCase[/COLOR]
                  If TypeName(sArray) = "Boolean" Then GoTo sBoolean
                  If Not IsNumeric(sArray) _
                        Or (sArray = 0 And Len(sArray) > 2) _
                        Or (sArray = -1 And Len(sArray) > 2) Then _
                        GoTo NextsArray
sBoolean:
                  If sArray = True And Len(sArray) > 2 Then sArray = 1
                  If sArray = False And Len(sArray) > 2 Then sArray = 0
                  If sArray > i Then i = sArray: j = 1
            End If
NextsArray:
      Next
      If m Or j Then udfMAX_HTN = IIf(n > i, n, i)
      Exit Function
[COLOR=#ff0000][B]ErrorCase:
      If ErrItm Then Itm = sArray
      udfMAX_HTN = CVErr(Itm)[/B][/COLOR]
End Function

Và hàm giờ đây có kiểu dữ liệu là Variant chứ không còn là dữ liệu Double đơn thuần nữa (tự ngẫm điều này thì tất cả các hàm của Excel đều có kiểu dữ liệu Variant)

Đặc biệt hơn, em thích chiêu ParamArray này quá Thầy ơi, nó có thể chứa công thức trong hàm luôn như:

=udfMax_HTN(I1:J6,VLOOKUP(RIGHT("NGHIA5")*1,$I$4:$J$7,2,TRUE),SUM(J4:J7))
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Theo ý kiến nhỏ của em, TRUE trong môi trường Excel và TRUE trong môi trường VBA là không bằng nhau, vì thế mới có vấn đề xảy ra như vậy. TRUE trong Excel = 1 còn TRUE trong VBA = -1, vì thế chính nội tại của nó mâu thuẫn với nhau như vậy nên nó bỏ qua khi gặp ô có giá trị TRUE. Và có lẽ điều này mà "anh BILL" cũng hợp bàn với "đàn em" dữ dội lắm để lấy giá trị nào, cuối cùng để "dĩ hòa di quý" thì "anh Bill" mới thống nhất lại rằng em TRUE nào ở trong cell thì bỏ qua, còn em TRUE nào nằm trong công thức thì tính là 1. Vì thế mới có chuyện lạ lùng là =MAX(A1) và A1 có giá trị là TRUE trong cell thì kết quả bằng 0 và công thức =MAX(TRUE) lại là 1.

Ta biết điều này là hoàn toàn phi lý... vậy nên ta cải tiến lại để ta xài thì không nhất thiết phải bắt chước nó 100%
-------------
Giờ sửa lại hàm udfMAX:
PHP:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item
  Dim dMax, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        If TypeName(Item) <> "Empty" Then
          If TypeName(Item) = "Boolean" Then tmp = -Item
          If TypeName(Item) = "Double" Then tmp = Item
          If TypeName(dMax) = "Empty" Or dMax < tmp Then dMax = tmp
        End If
      Next
    Else
      If TypeName(tmpArr) <> "Empty" Then
        If TypeName(tmpArr) = "Boolean" Then tmp = -tmpArr
        If TypeName(tmpArr) = "Double" Then tmp = tmpArr
        If TypeName(dMax) = "Empty" Or dMax < tmp Then dMax = tmp
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Xem ra là rút gọn hơn ấy chứ!
Nói tóm lại: Tôi không ủng hộ việc bắt chước MAX 100%. Tôi chỉ bắt chước MAX trong việc nó có thể hoạt động trên mảng thôi
Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Sửa tiếp:
Mã:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item, n As Long
  Dim dMax As Double, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        [COLOR=#ff0000]If TypeName(Item) = "Boolean" Then tmp = -Item[/COLOR]
        If TypeName(Item) = "Double" Then
          tmp = CDbl(Item)
          n = n + 1
        End If
        If n = 1 Or dMax < tmp Then dMax = tmp
      Next
    Else
      [COLOR=#ff0000]If TypeName(tmpArr) = "Boolean" Then
        tmp = -tmpArr
        If dMax < tmp Then dMax = tmp
      End If[/COLOR]
      If TypeName(tmpArr) = "Double" Then
        If dMax < tmpArr Then dMax = tmpArr
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Càng lúc càng dài hen!
ẹc... ẹc...

Hàm này vẫn chưa đúng kết quả ví dụ
=udfMax_NDU(100,{1,5,6,10})
Sẽ sai vì trả về là 10

Cái này thì tôi không đồng ý đâu nha!
Chúng ta có thể bắt chước MAX nhưng không nhất thiết bắt chước 100%... Vẫn có những chổ cải tiến theo kiểu khác
Nếu vùng A1:A10 chỉ có 1 chữ TRUE thì theo ý tôi =MAX(A1:A10,FALSE) phải cho kết quả = 1 mới hợp lý
Cũng giống như hàm MAX của Excel bị lỗi khi dữ liệu đầu vào bị lỗi nhưng hàm của tôi đã tránh được điều này (lỗi thì bỏ qua không tính)

đúng là đã lập riêng thì phải thêm những cái ưu việt hơn,

Bàn luận nhiều, giờ xin góp một code ngắn sau
PHP:
Function MaxVodoi2x(ParamArray DataArray())
    ''by Vodoi2x
    Dim subA, tmpA, iTem, tmP As Double, vMax As Double, bNum As Boolean
    For Each subA In DataArray
        tmpA = subA
        If Not IsArray(tmpA) Then tmpA = Array(tmpA)
        For Each iTem In tmpA
            If TypeName(iTem) = "Double" Or TypeName(iTem) = "Boolean" Then
                tmP = CDbl(IIf(TypeName(iTem) = "Boolean", -iTem, iTem))
                If Not bNum Or vMax < tmP Then vMax = tmP
                bNum = True
            End If
        Next iTem
    Next subA
    MaxVodoi2x = IIf(bNum, vMax, CVErr(2042))
End Function

Hàm sẽ trả về kết quả #N/A đối với trường hợp DataArray (dữ liệu) không có một số nào để tính toán MAX (trường hợp này hàm Max của excel trả về 0)

Hàm bỏ qua việc các lỗi xuất hiện ở dữ liệu (như bác ndu đề cập trên), hàm cũng bỏ qua dữ liệu là ngày, dữ liệu text ==> chỉ tính max với dữ liệu là số hoặc TRUE/FALSE


trong hàm này, đã gộp code cho trường hợp dữ liệu thành phần không phải Array thì chuyển nó thành Array ==> tốc độ có thể chậm đi đôi chút (vì phải qua 1 vòng lặp) -- TUY vậy thực tế tham số truyền vào tính max rất hiếm khi có quá nhiều thành phần đơn (không phải Array)- vì nễu nhiều quá thì nên tìm cách khác ghép lại==> NÊN chấp nhận được việc này, tốc độ tính ảnh hưởng không đáng kể
Vì thời gian có hạn, nên chưa test được nhiều, vậy các bạn test xem có còn gì cần hoàn thiện thêm thì cho ý kiến, xin cảm ơn
 
Upvote 0
Ta biết điều này là hoàn toàn phi lý... vậy nên ta cải tiến lại để ta xài thì không nhất thiết phải bắt chước nó 100%
-------------
Giờ sửa lại hàm udfMAX:
PHP:
Function udfMax_NDU(ParamArray sArray()) As Double
  Dim SubArr, tmpArr, Item
  Dim dMax, tmp
  On Error Resume Next
  For Each SubArr In sArray
    tmpArr = SubArr
    If IsArray(tmpArr) Then
      For Each Item In tmpArr
        If TypeName(Item) <> "Empty" Then
          If TypeName(Item) = "Boolean" Then tmp = -Item
          If TypeName(Item) = "Double" Then tmp = Item
          If TypeName(dMax) = "Empty" Or dMax < tmp Then dMax = tmp
        End If
      Next
    Else
      If TypeName(tmpArr) <> "Empty" Then
        If TypeName(tmpArr) = "Boolean" Then tmp = -tmpArr
        If TypeName(tmpArr) = "Double" Then tmp = tmpArr
        If TypeName(dMax) = "Empty" Or dMax < tmp Then dMax = tmp
      End If
    End If
  Next
  udfMax_NDU = dMax
End Function
Xem ra là rút gọn hơn ấy chứ!
Nói tóm lại: Tôi không ủng hộ việc bắt chước MAX 100%. Tôi chỉ bắt chước MAX trong việc nó có thể hoạt động trên mảng thôi
Ẹc... Ẹc...

Em chưa nói có lý hay phi lý, với TRUE thì Thầy tính = 1 hay -1 vậy?

------------------------------------------
Có thể là quan điểm của mỗi người, tuy nhiên, khi học quan điểm của em thường chọn vấn đề CHUẨN để thực thi, có thể không có chuyện mọi sự việc đều chính xác tuyệt đối, nhưng cái đầu "trái ổi" của em chắc chắn rằng không thể nào bằng hàng vạn chất xám của MicroSoft, vì thế em cho rằng hàm MAX làm như vậy là có nguyên do của nó. Và vì thế em chọn đó làm chuẩn để so sánh.

------------------------------------------
Vẫn biết viết hàm này là học thuật, thậm chí chẳng dùng nó vào đâu, nhưng ngồi phân tích cách mà hàm Excel vận hành như thế nào, cơ cấu chạy ra sao, kết quả như thế nào, lỗi xảy ra thì sẽ làm gì ... thì quả thật là điều thú vị, và hàm của mình viết ra đúng hay sai chỉ có hàm chuẩn trên Excel mới so sánh được, và từ những giá trị chuẩn mực đó mình sẽ viết những hàm khác ngoài Excel sẽ không bị cho là "lầm đường lỡ bước".
 
Upvote 0
Hàm này vẫn chưa đúng kết quả ví dụ
=udfMax_NDU(100,{1,5,6,10})
Sẽ sai vì trả về là 10



đúng là đã lập riêng thì phải thêm những cái ưu việt hơn,

Bàn luận nhiều, giờ xin góp một code ngắn sau
PHP:
Function MaxVodoi2x(ParamArray DataArray())
    ''by Vodoi2x
    Dim subA, tmpA, iTem, tmP As Double, vMax As Double, bNum As Boolean
    For Each subA In DataArray
        tmpA = subA
        If Not IsArray(tmpA) Then tmpA = Array(tmpA)
        For Each iTem In tmpA
            If TypeName(iTem) = "Double" Or TypeName(iTem) = "Boolean" Then
                tmP = CDbl(IIf(TypeName(iTem) = "Boolean", -iTem, iTem))
                If Not bNum Or vMax < tmP Then vMax = tmP
                bNum = True
            End If
        Next iTem
    Next subA
    MaxVodoi2x = IIf(bNum, vMax, CVErr(2042))
End Function

Hàm sẽ trả về kết quả #N/A đối với trường hợp DataArray (dữ liệu) không có một số nào để tính toán MAX (trường hợp này hàm Max của excel trả về 0)

Hàm bỏ qua việc các lỗi xuất hiện ở dữ liệu (như bác ndu đề cập trên), hàm cũng bỏ qua dữ liệu là ngày, dữ liệu text ==> chỉ tính max với dữ liệu là số hoặc TRUE/FALSE


trong hàm này, đã gộp code cho trường hợp dữ liệu thành phần không phải Array thì chuyển nó thành Array ==> tốc độ có thể chậm đi đôi chút (vì phải qua 1 vòng lặp) -- TUY vậy thực tế tham số truyền vào tính max rất hiếm khi có quá nhiều thành phần đơn (không phải Array)- vì nễu nhiều quá thì nên tìm cách khác ghép lại==> NÊN chấp nhận được việc này, tốc độ tính ảnh hưởng không đáng kể
Vì thời gian có hạn, nên chưa test được nhiều, vậy các bạn test xem có còn gì cần hoàn thiện thêm thì cho ý kiến, xin cảm ơn

Bạn kiểm tra lại, nếu vùng được chọn không có giá trị (rỗng) thì hàm bạn bị lỗi!

=MaxVodoi2x(B15:B16)
 
Upvote 0
Bạn kiểm tra lại, nếu vùng được chọn không có giá trị (rỗng) thì hàm bạn bị lỗi!

=MaxVodoi2x(B15:B16)

không phải lỗi, mà vì không có số nào để tính max nên hàm trả về là #N/A -- đây là cách báo cho người sử dụng biết là chọn vùng không có dữ liệu số để tìm MAX

tôi đã viết ở trên
Hàm sẽ trả về kết quả #N/A đối với trường hợp DataArray (dữ liệu) không có một số nào để tính toán MAX (trường hợp này hàm Max của excel trả về 0)

Hàm bỏ qua việc các lỗi xuất hiện ở dữ liệu (như bác ndu đề cập trên), hàm cũng bỏ qua dữ liệu là ngày, dữ liệu text ==> chỉ tính max với dữ liệu là số hoặc TRUE/FALSE
 
Upvote 0
Hàm Max có sẵn thì lấy ra dùng, để thời gian tranh luận và chỉnh sửa code đó ta làm những điều khác có ý nghĩa hơn, ví dụ như là giúp thành viên giải bài. Biết đó là sự tranh luận về học thuật, tuy nhiên ta nên tranh luận và bàn về những cái mới, những cái được cho là chưa hoàn hảo... Tôi thấy kiểu tranh luận này chẳng đáp ứng và ứng dụng gì nhiều cho người khác, vậy nên chăng chúng ta tiếp tục tranh luận? Tranh luận để làm gì? để chứng tỏ mình tài giỏi hơn người? hiểu biết hơn người? và tư duy hơn người?
 
Upvote 0
Upvote 0
Hàm Max có sẵn thì lấy ra dùng, để thời gian tranh luận và chỉnh sửa code đó ta làm những điều khác có ý nghĩa hơn, ví dụ như là giúp thành viên giải bài. Biết đó là sự tranh luận về học thuật, tuy nhiên ta nên tranh luận và bàn về những cái mới, những cái được cho là chưa hoàn hảo... Tôi thấy kiểu tranh luận này chẳng đáp ứng và ứng dụng gì nhiều cho người khác, vậy nên chăng chúng ta tiếp tục tranh luận? Tranh luận để làm gì? để chứng tỏ mình tài giỏi hơn người? hiểu biết hơn người? và tư duy hơn người?

Tôi thì ủng hộ TRANH LUẬN để tìm ra cái tốt hơn, nó cũng giúp cho tự bản thân chúng ta hoàn thiện kiến thức riêng cho mình
Nhấn mạnh là TRANH LUẬN VỀ KỸ THUẬT chứ không phải cãi lộn
Còn việc bạn nói hàm MAX có sẵn thì không nên viết ---> Cái này tôi không đồng ý
Lấy ví dụ về sort dữ liệu ---> Đây là công cụ có sẵn nhưng bạn có dùng được trên UserForm đâu ---> Muốn dùng chẳng lẽ lại "quăng" dữ liệu ra bảng tính để sort, xong lại "quăng" ngược vào UserForm?
Đó là tôi nói bạn đang thao tác trên Excel cũng còn có công cụ sort để mà dùng. Nếu mai này viết code trên VB6 thì lấy cái gì mà sort
Trở lại với hàm MAX: Cũng giống như y kiến trên, nó sẽ có tác dụng khi bạn dùng code trên các ứng dụng khác
 
Upvote 0
đúng là đã lập riêng thì phải thêm những cái ưu việt hơn,

Bàn luận nhiều, giờ xin góp một code ngắn sau
PHP:
Function MaxVodoi2x(ParamArray DataArray())
    ''by Vodoi2x
    Dim subA, tmpA, iTem, tmP As Double, vMax As Double, bNum As Boolean
    For Each subA In DataArray
        tmpA = subA
        If Not IsArray(tmpA) Then tmpA = Array(tmpA)
        For Each iTem In tmpA
            If TypeName(iTem) = "Double" Or TypeName(iTem) = "Boolean" Then
                tmP = CDbl(IIf(TypeName(iTem) = "Boolean", -iTem, iTem))
                If Not bNum Or vMax < tmP Then vMax = tmP
                bNum = True
            End If
        Next iTem
    Next subA
    MaxVodoi2x = IIf(bNum, vMax, CVErr(2042))
End Function

Xét về mặt giải thuật thì code này cũng gần giống cái của tôi. Tuy nhiên bạn đã cho các phần tử đơn vào mảng để duyệt 1 lần nên có rút gọn hơn
Lúc đầu tôi cũng định như vậy nhưng cuối cùng vẫn phân ra 2 trường hợp riêng để dễ kiểm soát (mai này còn phải test thêm trên các ứng dụng khác nữa)
Nói chung là tùy quan điểm của mỗi người nhưng giải thuật vẫn là cái mấu chốt nhất giúp ta giải quyết vấn đề
 
Upvote 0
Tôi test trên máy tôi kết quả là 100 bạn à!

Em cũng đã test và kết quả là 100 trên máy của em Excel2007

Xét về mặt giải thuật thì code này cũng gần giống cái của tôi. Tuy nhiên bạn đã cho các phần tử đơn vào mảng để duyệt 1 lần nên có rút gọn hơn
Lúc đầu tôi cũng định như vậy nhưng cuối cùng vẫn phân ra 2 trường hợp riêng để dễ kiểm soát (mai này còn phải test thêm trên các ứng dụng khác nữa)
Nói chung là tùy quan điểm của mỗi người nhưng giải thuật vẫn là cái mấu chốt nhất giúp ta giải quyết vấn đề

Trời ơi, học trò của Thầy nên quan điểm giống nhau quá! Em nghĩ sau khi đưa ra kết quả gần như hàm CHUẨN sẽ tinh gọn lại, tỉa tót những thứ dư thừa và tiếp theo sẽ nghĩ tới đo tốc độ.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi thì ủng hộ TRANH LUẬN để tìm ra cái tốt hơn, nó cũng giúp cho tự bản thân chúng ta hoàn thiện kiến thức riêng cho mình
Nhấn mạnh là TRANH LUẬN VỀ KỸ THUẬT chứ không phải cãi lộn
Còn việc bạn nói hàm MAX có sẵn thì không nên viết ---> Cái này tôi không đồng ý
Lấy ví dụ về sort dữ liệu ---> Đây là công cụ có sẵn nhưng bạn có dùng được trên UserForm đâu ---> Muốn dùng chẳng lẽ lại "quăng" dữ liệu ra bảng tính để sort, xong lại "quăng" ngược vào UserForm?
Đó là tôi nói bạn đang thao tác trên Excel cũng còn có công cụ sort để mà dùng. Nếu mai này viết code trên VB6 thì lấy cái gì mà sort
Trở lại với hàm MAX: Cũng giống như y kiến trên, nó sẽ có tác dụng khi bạn dùng code trên các ứng dụng khác
Vậy ta có thể tham chiếu đến thư viện của nó mà sử dụng chắc là được chứ.
Mỗi ngôn ngữ đều có cách xử lý riêng ví dụ anh nói sort ở VB6 thì ta có thể dùng ADO để sort, rất đơn giản mà.
 
Upvote 0
Vậy ta có thể tham chiếu đến thư viện của nó mà sử dụng chắc là được chứ.
Mỗi ngôn ngữ đều có cách xử lý riêng ví dụ anh nói sort ở VB6 thì ta có thể dùng ADO để sort, rất đơn giản mà.

Vâng!
Bởi vậy tôi mới nói tùy quan điểm mỗi người
Ác cái tôi không rành ADO nên tôi phải tự viết hàm mà xài thôi
Ẹc... Ẹc...
-------------------------
Trời ơi, học trò của Thầy nên quan điểm giống nhau quá!
Cái này không nên nói bậy nha (khiến người khác phải buồn lòng)
Tôi chưa từng dạy bạn ấy điều gì và tự nghĩ cũng không đủ khả năng để dạy ---> Bởi vì bạn ấy đã rất giỏi và thông minh rồi
 
Lần chỉnh sửa cuối:
Upvote 0
Vâng!
Bởi vậy tôi mới nói tùy quan điểm mỗi người
Ác cái tôi không rành ADO nên tôi phải tự viết hàm mà xài thôi
Ẹc... Ẹc...
-------------------------

Cái này không nên nói bậy nha (khiến người khác phải buồn lòng)
Tôi chưa từng dạy bạn ấy điều gì và tự nghĩ cũng không đủ khả năng để dạy ---> Bởi vì bạn ấy đã rất giỏi và thông minh rồi
Quan điểm ở đây là thuật toán cho đúng, sau đó mới tính tới chuyện tinh gọn sau, rồi mới nghĩ tới tốc độ.

Em nói em là học trò của Thầy, chứ có nói ai đâu Thầy ơi! Dù Thầy chẳng phải trên danh nghĩa Thầy - Trò, nhưng Thầy đã tận tình hướng dẫn, giúp đỡ cho em còn hơn cả Thầy truyền đạt kiến thức cho học trò nữa nên em vẫn muốn gọi là Thầy.

PHP:
Function MaxVodoi2x(ParamArray DataArray())
    ''by Vodoi2x
    Dim subA, tmpA, iTem, tmP As Double, vMax As Double, bNum As Boolean
    For Each subA In DataArray
        tmpA = subA
        If Not IsArray(tmpA) Then tmpA = Array(tmpA)
        For Each iTem In tmpA
            If TypeName(iTem) = "Double" Or TypeName(iTem) = "Boolean" Then
                tmP = CDbl(IIf(TypeName(iTem) = "Boolean", -iTem, iTem))
                If Not bNum Or vMax < tmP Then vMax = tmP
                bNum = True
            End If
        Next iTem
    Next subA
    MaxVodoi2x = IIf(bNum, vMax, CVErr(2042))
End Function


Bạn kiểm tra lại, nếu vùng được chọn không có giá trị (rỗng) thì hàm bạn bị lỗi!

=MaxVodoi2x(B15:B16)


Bạn nên chăng phải sửa lại tí?
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn kiểm tra lại, nếu vùng được chọn không có giá trị (rỗng) thì hàm bạn bị lỗi!

=MaxVodoi2x(B15:B16)

Bạn nên chăng phải sửa lại tí?

Không hiểu là bạn muốn sửa gì, bạn đọc bài #28 trên chưa

không phải lỗi, mà vì không có số nào để tính max nên hàm trả về là #N/A -- đây là cách báo cho người sử dụng biết là chọn vùng không có dữ liệu số để tìm MAX (tức là vùng hơi vô duyên, không có số nào cả để tìm max - hoặc các số bị định dạng dạng ký tự (text)

tôi cũng đã viết ở trên
Hàm sẽ trả về kết quả #N/A đối với trường hợp DataArray (dữ liệu) không có một số nào để tính toán MAX (trường hợp này hàm Max của excel trả về 0)

Hàm bỏ qua việc các lỗi xuất hiện ở dữ liệu (như bác ndu đề cập trên), hàm cũng bỏ qua dữ liệu là ngày, dữ liệu text ==> chỉ tính max với dữ liệu là số hoặc TRUE/FALSE

Còn nếu bạn muốn trả về giá trị 0 dù dãy dữ liệu nhập vào là toàn ký tự, hay gồm các cell rỗng NHƯ HÀM MAX của EXCEL, thì sửa 1 lệnh cuối cùng thôi
từ
PHP:
MaxVodoi2x = IIf(bNum, vMax, CVErr(2042))
thành
PHP:
MaxVodoi2x = vMax
thì khi này kết quả sẽ trả về 0 khi tất cả các cell đều rỗng
 
Lần chỉnh sửa cuối:
Upvote 0
Không hiểu là bạn muốn sửa gì, bạn đọc bài #28 trên chưa

không phải lỗi, mà vì không có số nào để tính max nên hàm trả về là #N/A -- đây là cách báo cho người sử dụng biết là chọn vùng không có dữ liệu số để tìm MAX

tôi cũng đã viết ở trên


Còn nếu bạn muốn trả về giá trị 0 dù dãy dữ liệu nhập vào là ký tự, hay gồm các cell rỗng thì sửa 1 lệnh cuối cùng thôi
từ
PHP:
MaxVodoi2x = IIf(bNum, vMax, CVErr(2042))
thành
PHP:
MaxVodoi2x = vMax
thì khi này kết quả sẽ trả về 0 khi tất cả các cell đều rỗng

Theo tôi được biết, hàm SUM, MAX, MIN ... khi gặp vùng dữ liệu rỗng đều cho ra giá trị 0 nên hàm bạn cho ra lỗi là SAI, chỉ đơn giản vậy thôi.

Còn việc bạn chỉnh lại, tôi e rằng lại bỏ qua vùng lỗi của dữ liệu như Thầy NDU.
 
Upvote 0
Theo tôi được biết, hàm SUM, MAX, MIN ... khi gặp vùng dữ liệu rỗng đều cho ra giá trị 0 nên hàm bạn cho ra lỗi là SAI, chỉ đơn giản vậy thôi.

Còn việc bạn chỉnh lại, tôi e rằng lại bỏ qua vùng lỗi của dữ liệu như Thầy NDU.

Tùy quan niệm thôi bạn ah, Vùng không có dữ liệu mà MAX lại =0 thì cũng là hơi lạ,

Tùy mục đích sử dụng thôi
tôi đã viết trên rõ rồi phạm vi ứng dụng của hàm mà: cho phép bỏ qua các lỗi của các dữ liệu nhập - điều này có phạm vi ứng dụng của nó,
Còn nếu bạn muốn thế nào thì cứ tùy biến thôi, thêm IF bẫy IsError thôi- chuyện nay đâu khó với việc tương thêm mắm muối gia vị vào
 
Lần chỉnh sửa cuối:
Upvote 0
Kết luận cho vấn đề thảo luận này, bản thân tôi rút ra những bài học như sau:

- Khẳng định rằng, Với khả năng của tôi, khó có thể viết giống như hàm của Excel (hiển nhiên)

- Tôi học thêm được nhiều cách biến hóa từ ParamArray mà tôi được học từ Thầy NDU

- Học thêm được cách bẫy các kiểu lỗi của Excel

- Khả năng tư duy được nâng cao.

==========================================

Cám ơn các Thầy, các Anh đã nhiệt tình tham gia topic này để mỗi người nhận thấy khiếm khuyết của mình mà sửa, học được cái hay của người khác.
 
Upvote 0
Theo tôi được biết, hàm SUM, MAX, MIN ... khi gặp vùng dữ liệu rỗng đều cho ra giá trị 0 nên hàm bạn cho ra lỗi là SAI, chỉ đơn giản vậy thôi.

Còn việc bạn chỉnh lại, tôi e rằng lại bỏ qua vùng lỗi của dữ liệu như Thầy NDU.

Không thể nói như thế được Nghĩa à.
Tôi theo dõi chủ đề và thật khâm phục các bạn là các bạn có thể tranh luận lâu như thế.
Bất kể cái máy nào muốn đánh giá tốt, xấu thì phải dựa trên các tiêu chuẩn. Mỗi định lý chỉ đúng với một tập giả thiết cụ thể. Các bạn đã thống nhất với nhau về tiêu chí chưa? Nếu đã thì chỉ cho tôi biết.
Chưa thống nhất với nhau về các giả thiết thì trên cơ sở nào đánh giá code là đúng, sai?
Bạn Nghĩa muốn viết code bắt trước Excel 100 %? Thì bạn có quyền đó nếu cách "xử lý" của Excel thỏa yêu cầu của bạn. Nhưng có thể cách xử lý của Excel trong một số tình huống không đạt yêu cầu của vodoi2x. Tại sao? Tôi sẽ viết sau.
Bạn Nghĩa chấp nhận cách Excel coi TRUE / FALSE như thế như thế nhưng với tôi thì tôi không chấp nhận cách đó vì tôi viết hàm cho th đặc thù của tôi khi mà TRUE thì LUÔN là 1 và FALSE LUÔN là 0.
Bạn Nghĩa có thể chấp nhận dữ liệu thiếu / rỗng trong khi vodoi2x không chấp nhận việc rỗng = 0. Vì sao? Vì vodoi2x cất công viết hàm để giải bài toán đặc thù nào đấy mà Max kia chỉ là kết quả trung gian. Nếu chấp nhận rỗng = 0 thì sẽ có Max để tính kết quả cuối cùng, nhưng kết quả đó là sai vì trong th cụ thể của vodoi2x thì chỉ chấp nhận kết quả khi dữ liệu vào là đúng và đầy đủ. Nếu vodoi2x không thông báo lỗi cho người dùng code của mình biết thì anh ta không ý thức được là kết quả cuối cùng không đúng. Tùy vào nhu cầu mà chấp nhận hay không chấp nhận dữ liệu thiếu. Tôi đã viết code thì có nghĩa là tôi xử lý theo cách của mình, phù hợp với nhu cầu của mình. Chả lý gì mà tôi phải bắt chước Excel 100 %.
Tóm lại để tranh luận, để đánh giá code thì trước tiên phải thống nhất với nhau một vài điểm làm cơ sở. User_Max? Thế chỉ chấp nhận số hay cả giá trị lôgíc? Nếu cả TRUE / FALSE thì LUÔN là 1 / 0 hay TRUE lúc này là 1 lúc khác là 1000 (hơi phi lý)? Có chấp nhận dữ liệu rỗng không? Nếu chấp nhận thì coi nó là 0 hay coi nó là giá trị nhỏ nhất có thể? Mà ta xét số nguyên hay số nói chung? v...v
Nếu chưa thống nhất được với nhau về những điểm như thế thì trên cơ sở nào nói code là sai? Bạn Nghĩa viết cho nhu cầu của mình với những giả thiết, qui ước "ngầm" như thế này trong khi bạn vodoi2x lại viết cho nhu cầu của mình với những giả thiết, qui ước "ngầm" như thế kia. Thế thì có tranh luận tới ngày tận thế + thêm 1 ngày cũng không thể có tiếng nói chung được.
 
Upvote 0
Không thể nói như thế được Nghĩa à.
Tôi theo dõi chủ đề và thật khâm phục các bạn là các bạn có thể tranh luận lâu như thế.
Bất kể cái máy nào muốn đánh giá tốt, xấu thì phải dựa trên các tiêu chuẩn. Mỗi định lý chỉ đúng với một tập giả thiết cụ thể. Các bạn đã thống nhất với nhau về tiêu chí chưa? Nếu đã thì chỉ cho tôi biết.
Chưa thống nhất với nhau về các giả thiết thì trên cơ sở nào đánh giá code là đúng, sai?

Cám ơn bác đã đưa ra đúng theo tiêu chí đánh giá khách quan / minh bạch, không bị chi phối gì cả

Khi viết 1 code thành phẩm thì người viết đưa ra những giả định và những chấp nhận về dữ liệu phạm vi hoạt động của hàm, cũng như cách thức kết quả trả về rui

Trên tôi đã đưa ra đầy đủ hướng dẫn, giới hạn đối với số liệu, kết quả trả về , phân tích cả về cái gộp code cho ngắn gọn

Nhưng dường như cố tình không đọc hướng dẫn kèm theo để sử dụng hợp lý - khác nào uống Viên thuốc C sủi, mà lại cho vào mệng uống thẳng luôn -chưa biết nhưng không đọc hướng dẫn cách dùng - Cần phải học lại "cách dùng" sao cho chuẩn.

Vì vậy đúng sai phải dựa trên mục tiêu / các giới hạn phạm vi hoạt động / cách thức hoạt động của code mà tác giả đưa ra. còn muốn hỏi hay xin học thêm thì người hỏi phải viết cách khác.

Có như vậy mới gọi là trao đổi thảo luận
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu chúng ta dùng VBA để tạo ra hàm giống hệt hàm của Excel có thể không được. Vì lý do sau:

- Excel có nguyên tắc về đối số truyền vào: tham số đưa vào là Range/Tham chiếu thì nó sẽ kiểm tra kiểu gía trị hợp lệ trong Range.Value để đưa vào phép tính, nếu tham số đưa vào là gía trị như là chuỗi "1", "10/10/2012" hoặc dạng Boolean TRUE, FALSE nó lập tức chuyển đổi/convert giá trị về dạng số và đưa vào phép tính.
- Hàm UDF trong VBA phải dùng khai báo ParamArray BienMang() để cho phép hàm được nhập 1 hay nhiều đối số gần giống hàm Excel. Các phần tử mảng BienMang(I) (danh sách các đối số của hàm) đã bị đưa về dạng giá trị trước khi ta có thể kiểm tra xem nó có phải là tham chiếu hay không.

Vì lý do trên mà chúng ta có thể không làm được một hàm UDF trong VBA giống hệt của Excel.

Ví dụ hai công thức dạng dưới đây kết quả sẽ khó có thể giống nhau:

=MAX(1, "10", C1:H10, "10/10/2012", A1, TRUE)
=UDF_MAX(1, "10", C1:H10, "10/10/2012", A1, TRUE)
(A1 chứa giá trị có thể chuyển đổi)

Nếu lập trình hàm trong add-in dạng XLL thì có thể làm giống được hàm của Excel ít nhất về kết quả tính toán.

Còn vấn đề về báo lỗi thì theo tôi tư duy kiểu Excel là chuẩn, không nên convert lỗi về giá trị 0. Hàm nên trả về mã lỗi ngay để người dùng sửa lại nguồn đưa vào. Hơn nữa trong tình huống nào đó, số 0 là có ý nghĩa với người sử dụng, trong khi lỗi là không gía trị sử dụng.
 
Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom