Hàm phần bù của một range

Liên hệ QC

cuongdoannhat

Thành viên chính thức
Tham gia
27/6/09
Bài viết
67
Được thích
39
Chào các bạn.
Trong vba có hàm Intersect, hàm Union là hai hàm trả về kết quả là giao, hợp của 2 range. Vậy có hàm nào là hàm phần bù của một range hoặc hiệu của hai 2 range không nhỉ? Nếu không có mình phải code như thế nào? Nhờ các bạn giúp dùm mình với
 
Chào các bạn.
Trong vba có hàm Intersect, hàm Union là hai hàm trả về kết quả là giao, hợp của 2 range. Vậy có hàm nào là hàm phần bù của một range hoặc hiệu của hai 2 range không nhỉ? Nếu không có mình phải code như thế nào? Nhờ các bạn giúp dùm mình với
Bạn cho 1 ví dụ cụ thể đi, rồi mọi người sẽ cố gắng viết code đáp ứng nhu cầu của bạn
 
Upvote 0
Hàm phần bù của một range, hàm hiệu của hai range mang ý nghĩa như đại số tập hợp vậy. Ví dụ mình có một range a=range("A1:B10:) thì phần bù của a là toàn bộ các cell của sheet bỏ đi a.
Và b=range("B5:C20") thì a-b sẽ là những cell thuộc a mà không thuộc b tức là c=union(""A1:B4","A5C10"). Xin cảm ơn các bạn.
 
Upvote 0
Xin mạo muội đề xuất ý tưởng của mình. Mình muốn có hàm phần bù và hàm hiệu của range với mục đích thực hiện các phép toán đại số tập hợp. Bởi vì mình nghĩ các phép toán đại số tập hợp đều dựa trên các phép giao, hợp, phần bù và hiệu cơ bản này. Nhưng mình tìm mãi trong thư viện của vba vẫn không biết hàm nào là phần bù và hiệu.
 
Upvote 0
Cảm ơn bạn SA_DQ đã cho link. Đúng là mình đã tìm được ý tưởng từ bài này. Nhưng code còn lung tung quá.
 
Upvote 0
Hàm phần bù của một range, hàm hiệu của hai range mang ý nghĩa như đại số tập hợp vậy. Ví dụ mình có một range a=range("A1:B10:) thì phần bù của a là toàn bộ các cell của sheet bỏ đi a.
Và b=range("B5:C20") thì a-b sẽ là những cell thuộc a mà không thuộc b tức là c=union(""A1:B4","A5C10"). Xin cảm ơn các bạn.
Cái vụ HIỆU thì tôi hiểu, code thế này
PHP:
Function InvertRange(ByVal SrcRng As Range, ByVal RejRng As Range) As Range
  Dim Clls As Range, InvRng As Range
  On Error Resume Next
  For Each Clls In SrcRng
    If Intersect(Clls, RejRng) Is Nothing Then
      If InvRng Is Nothing Then
         Set InvRng = Clls
      Else:
        Set InvRng = Union(InvRng, Clls)
      End If
    End If
  Next
  Set InvertRange = InvRng
End Function
Thí nghiệm thế này:
PHP:
Sub Test()
  Dim SrcRng As Range, RejRng As Range
  On Error Resume Next
  Set SrcRng = Application.InputBox("Chon vung", Type:=8)
  Set RejRng = Application.InputBox("Chon vùng can bo", Type:=8)
  With InvertRange(SrcRng, RejRng)
    .Select: .Interior.ColorIndex = 5
  End With
End Sub
-------------------------
Còn cái vụ "BÙ" bạn vui lòng cho lại 1 ví dụ khác đi.
Chẳng hạn Rng1 = Range("A1:C10") và Rng2 = Range("B5:H20") ---> Vậy "BÙ" sẽ cho kết quả = cái gì?
 
Upvote 0
Mình lại hiểu là vầy

Hieu_Bu.JPG

Hiệu là các ô màu nền xanh lam & bù là các ô màu xám?
 
Upvote 0
Đọc kỹ lại mới thấy cái vụ "BÙ" và "HIỆU" cũng y chang nhau thôi ---> Chẳng qua cái vụ "BÙ" mà tác giả nói thì SrcRng được tính cho nguyên sheet
Tuy nhiên, vòng lập mà quét nguyên 1 sheet thì hổng biết đến bao giờ mới xong
Hic...
 
Upvote 0
Phép bù là phép toán một ngôi (chỉ có một toán hạng). Ví dụ a là toàn bộ các cells của một sheet, b=range("A1:C10") thì khi đó =BU(b) sẽ là a-b. Có nghĩa là một range gồm các vùng "D1:XFD10" và "A11:XFD1048576" (mình đang dùng Office 2010)
 
Upvote 0
Bạn ndu96081631 nói đúng ý của mình đấy. Vấn đề là phải quét qua toàn bộ các cells trong một sheet mình cũng thấy ngại quá.
 
Upvote 0
Phép bù là phép toán một ngôi (chỉ có một toán hạng). Ví dụ a là toàn bộ các cells của một sheet, b=range("A1:C10") thì khi đó =BU(b) sẽ là a-b. Có nghĩa là một range gồm các vùng "D1:XFD10" và "A11:XFD1048576" (mình đang dùng Office 2010)
Nói cho cùng thì nó cũng là hiệu 2 Range mà thôi
Làm chắc là được, tuy nhiên tôi thấy nhu cầu áp dụng thực tế của nó khá hạn hẹp. Xin hỏi: Bạn định xây dựng hàm này nhằm mục đích gì?
Tôi hỏi thế là vì với Excel 2010 mà dùng vòng lập theo cách thông thường thì e rằng chạy xong 1 code phải mất cả giờ đồng hồ. Nếu biết được mục đích thật sự của bạn, có thể mọi người sẽ có lời khuyên về một hướng đi khác, giải thuật khác, miễn ra cùng 1 kết quả cho bạn
Bạn thấy sao?
 
Upvote 0
Tạm thời nghĩ ra được cái "củ chuối" này
PHP:
Function GetBigRange(ByVal SrcRng As Range) As Range
  Set GetBigRange = SrcRng.Parent.Range(Replace(SrcRng.Address, ",", ":"))
End Function
PHP:
Function InvertRange(ByVal RejRng As Range) As Range
  Dim BigRng As Range, Tmp As Range, Clls As Range
  Dim Tmp1 As Range, Tmp2 As Range, Tmp3 As Range, Tmp4 As Range
  On Error Resume Next
  Set BigRng = GetBigRange(RejRng)
  With BigRng.Parent
    Set Tmp1 = .Range(.Rows(1), .Rows(BigRng.Row - 1))
    Set Tmp2 = .Range(.Rows(BigRng.Row + BigRng.Rows.Count), .Rows(Cells.Rows.Count))
    Set Tmp3 = .Range(.Columns(1), .Columns(BigRng.Column - 1))
    Set Tmp4 = .Range(.Columns(BigRng.Column + BigRng.Columns.Count), .Columns(Cells.Columns.Count))
  End With
  If Not Tmp1 Is Nothing Then
    If Tmp Is Nothing Then
      Set Tmp = Tmp1
    Else
      Set Tmp = Union(Tmp, Tmp1)
    End If
  End If
  If Not Tmp2 Is Nothing Then
    If Tmp Is Nothing Then
      Set Tmp = Tmp2
    Else
      Set Tmp = Union(Tmp, Tmp2)
    End If
  End If
  If Not Tmp3 Is Nothing Then
    If Tmp Is Nothing Then
      Set Tmp = Tmp3
    Else
      Set Tmp = Union(Tmp, Tmp3)
    End If
  End If
  If Not Tmp4 Is Nothing Then
    If Tmp Is Nothing Then
      Set Tmp = Tmp4
    Else
      Set Tmp = Union(Tmp, Tmp4)
    End If
  End If
  For Each Clls In BigRng
    If Intersect(Clls, RejRng) Is Nothing Then
      Set Tmp = Union(Tmp, Clls)
    End If
  Next
  Set InvertRange = Tmp
End Function
----------------
Thí nghiệm
PHP:
Sub Test()
  Dim RejRng As Range
  On Error Resume Next
  Set RejRng = Application.InputBox("Chon vùng can bo", Type:=8)
  With InvertRange(RejRng)
    .Parent.Activate
    .Select: .Interior.ColorIndex = 6
  End With
End Sub
Đương nhiên là code chạy rất nhanh vì không phải quét toàn bộ sheet
Các bạn hãy chạy thử nghiệm xem có lỗi gì không nha!
 

File đính kèm

Upvote 0
Tạm thời nghĩ ra được cái "củ chuối" này
Sub Test()
Dim RejRng As Range
On Error Resume Next
Set RejRng = Application.InputBox("Chon vùng can bo", Type:=8)
With InvertRange(RejRng)
.Parent.Activate
.Select: .Interior.ColorIndex = 6
End With
End Sub[/php]
Đương nhiên là code chạy rất nhanh vì không phải quét toàn bộ sheet
Các bạn hãy chạy thử nghiệm xem có lỗi gì không nha!

Thử test thì file bạn gửi,
Không nhanh ah, a thử test lại với vùng range chọn khi chạy là B2:D2,IK65530:IK65531 (giữ ctrl để chọn k liên tiếp, có mấy ô thôi ah) xem sao???
Chạy lâu mà không ra kết quả
 
Upvote 0
Thử test thì file bạn gửi,
Không nhanh ah, a thử test lại với vùng range chọn khi chạy là B2:D2,IK65530:IK65531 (giữ ctrl để chọn k liên tiếp, có mấy ô thôi ah) xem sao???
Chạy lâu mà không ra kết quả
Đành chịu vậy! Nên tôi mới nói là "củ chuối"
Vùng không liên tục nhưng càng gần nhau thì code càng nhanh
Code hoạt động với Range luôn có giới hạn về tốc độ... cải tiến giải thuật chỉ có thể tăng tốc phần nào mà thôi.
Bởi thế nên ngay từ đầu tôi đã hỏi tác giả về mục đích sử dụng để nghiên cứu thêm hướng khác
 
Upvote 0
Đúng là củ chuối thật,

Thử lại chạy vẫn thế, với vùng vừa vừa xa nhau 1000 dòng hoặc 1000 cột là chậm rồi

Không có cách nào khác ah, a?
 
Upvote 0
Đúng là củ chuối thật,
Thử lại chạy vẫn thế, với vùng vừa vừa xa nhau 1000 dòng hoặc 1000 cột là chậm rồi
Không có cách nào khác ah, a?
Hỏi lại: Thật ra bạn cần cái này để làm gì? Cùng 1 kết quả ta có thể giải quyết bằng nhiều phương pháp mà
 
Upvote 0
Nhu cầu thì chủ câu hỏi nói rồi đó ah,

Thấy các Add Ins (như ASAP Utilities) của họ có thể làm được, chắc hẳn phải có cách?
 
Upvote 0
Web KT

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

Back
Top Bottom