Tạo hàm so sánh 2 danh sách (1 người xem)

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

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,913
Thấy có nhiều bạn hỏi về chủ đề so sánh 2 danh sách. Trên diễn đàn cũng đã có nhiều bài trả lời bằng nhiều thuật toán khác nhau. Hôm nay tôi viết 1 hàm tổng quát về Compare2List với 3 tùy chọn:

- Tìm các phần tử có cả trong danh sách 1 và danh sách 2
- Tìm các phần tử có trong danh sách 1 mà không có trong danh sách 2
- Tìm các phần tử có trong danh sách 2 mà không có trong danh sách 1

Code như sau:
PHP:
Function Compare2List(ByVal sArray1, ByVal sArray2, ByVal CompareMod As Long)
  Dim Dic1, Dic2, Item, Item1, Item2, TmpKeys1, TmpKeys2, Arr() as String
  Dim Tmp1 As String, Tmp2 As String, j As Long, ub As Long
  On Error Resume Next
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  For Each Item1 In sArray1
    If CStr(Item1) <> "" Then
      Tmp1 = CStr(Item1)
      If Not Dic1.Exists(Tmp1) Then Dic1.Add Tmp1, ""
    End If
  Next
  TmpKeys1 = Dic1.Keys
  For Each Item2 In sArray2
    If CStr(Item2) <> "" Then
      Tmp2 = CStr(Item2)
      If Not Dic2.Exists(Tmp2) Then Dic2.Add Tmp2, ""
    End If
  Next
  TmpKeys2 = Dic2.Keys
  ub = IIf(Dic1.Count > Dic2.Count, Dic1.Count, Dic2.Count)
  ReDim Arr(1 To ub, 1 To 1)
  Select Case CompareMod
    Case 1
      For Each Item In TmpKeys1
        If Dic2.Exists(CStr(Item)) Then
          j = j + 1
          Arr(j, 1) = CStr(Item)
        End If
      Next
    Case 2
      For Each Item In TmpKeys1
        If Not Dic2.Exists(CStr(Item)) Then
          j = j + 1
          Arr(j, 1) = CStr(Item)
        End If
      Next
    Case 3
      For Each Item In TmpKeys2
        If Not Dic1.Exists(CStr(Item)) Then
          j = j + 1
          Arr(j, 1) = CStr(Item)
        End If
      Next
  End Select
  Compare2List = Arr
End Function
Áp dụng Ví dụ bạn có 2 danh sách: DS1 nằm ở A2:A60000 và DS2 nằm ở B2:B60000
1> Để tìm các phần tử có trong 2 danh sách
PHP:
Sub Main1()
  Dim sArray1, sArray2, Arr, TG As Double
  On Error Resume Next
  TG = Timer
  sArray1 = Range("A2:A65536").Value
  sArray2 = Range("B2:B65536").Value
  Arr = Compare2List(sArray1, sArray2, 1)
  Range("D2").Resize(UBound(Arr, 1)).Value = Arr
  MsgBox Timer - TG
End Sub
2> Để tìm các phần tử có trong danh sách 1 mà không có trong danh sách 2
PHP:
Sub Main2()
  Dim sArray1, sArray2, Arr, TG As Double
  On Error Resume Next
  TG = Timer
  sArray1 = Range("A2:A65536").Value
  sArray2 = Range("B2:B65536").Value
  Arr = Compare2List(sArray1, sArray2, 2)
  Range("E2").Resize(UBound(Arr, 1)).Value = Arr
  MsgBox Timer - TG
End Sub
3> Để tìm các phần tử có trong danh sách 2 mà không có trong danh sách 1
PHP:
Sub Main3()
  On Error Resume Next
  Dim sArray1, sArray2, Arr, TG As Double
  TG = Timer
  sArray1 = Range("A2:A65536").Value
  sArray2 = Range("B2:B65536").Value
  Arr = Compare2List(sArray1, sArray2, 3)
  Range("F2").Resize(UBound(Arr, 1)).Value = Arr
  MsgBox Timer - TG
End Sub
Code này dùng phương pháp xử lý mảng nên tốc độ rất cao. Thử nghiệm với 2 danh sách dài 65000 dòng, ra kết quả trong vòng 4 giây
Mời xem file và kiểm tra
 

File đính kèm

Tôi không hiểu lắm về mã nguồn của anhtuan1066, nhưng xin được cải tiến một chút để linh hoạt hơn khi quy định các vùng dữ liệu đầu vào và vùng dữ liệu đầu ra.

Cụ thể được ghi trong file đính kèm. Để tiện, tôi xoá một số macro của anhtuan66 (chỉ giữ lại 1) và đưa thêm macro có tên Run1, có dùng phím nóng là Ctrl - R.

Cũng xin nói thêm: Việc đưa tham số của Macro ngay trên bảng tính có thể là giải pháp tốt cho nhiều trường hợp khác, và đã lâu, tôi muốn thể hiện nó.
Nay nhờ bài của anhtuan, tôi có cơ hội. Một lần nữa xin cảm ơn.
 

File đính kèm

Upvote 0
Tôi không hiểu lắm về mã nguồn của anhtuan1066, nhưng xin được cải tiến một chút để linh hoạt hơn khi quy định các vùng dữ liệu đầu vào và vùng dữ liệu đầu ra.
Cụ thể được ghi trong file đính kèm. Để tiện, tôi xoá một số macro của anhtuan66 (chỉ giữ lại 1) và đưa thêm macro có tên Run1, có dùng phím nóng là Ctrl - R.
Cũng xin nói thêm: Việc đưa tham số của Macro ngay trên bảng tính có thể là giải pháp tốt cho nhiều trường hợp khác, và đã lâu, tôi muốn thể hiện nó.
Nay nhờ bài của anhtuan, tôi có cơ hội. Một lần nữa xin cảm ơn.
Ai lại làm thế! Cái bạn làm có nghĩa là THỰC THI LỆNH TỪ 1 CHUỔI CHỨA CÂU LỆNH
Vậy phải xem bài này:
http://www.giaiphapexcel.com/forum/showthread.php?34190-L%C3%A0m-sao-%C4%91%E1%BB%83-ch%E1%BA%A1y-1-l%E1%BB%87nh-t%E1%BB%AB-1-chu%E1%BB%95i-%28c%C3%B3-c%C3%BA-ph%C3%A1p-c%E1%BB%A7a-1-l%E1%BB%87nh%29
Và code của bạn tôi sửa lại thành:
PHP:
Sub ExecuteCommand()
  If ActiveCell = "" Then Exit Sub
  With ThisWorkbook.VBProject
    .VBComponents.Add(1).Name = String(30, "z")
    With .VBComponents(String(30, "z")).CodeModule
      .InsertLines .CountOfLines + 1, _
       "Sub Main()" & vbLf & _
         "Dim Arr" & vbLf & _
         "On Error Resume Next" & vbLf & _
         "Arr = Compare2List(" & ActiveCell.Value & ")" & vbLf & _
         "ActiveCell.Offset(1).Resize(Ubound(Arr,1)).Value = Arr" & vbLf & _
       "End Sub"
    End With
    Application.Run "Main"
    .VBComponents.Remove .VBComponents(String(30, "z"))
  End With
End Sub
PHP:
Sub Run1()
  Dim TG As Double
  TG = Timer
  ExecuteCommand
  MsgBox Timer - TG
End Sub
Cái chiêu ExecuteCommand này có thể dùng cho bất kỳ trường hợp nào, không riêng gì bài này đâu (đấy gọi là TỔNG QUÁT)
Lưu ý chổ này khi chạy code:
- Đối với những code có can thiệp vào việc THÊM CODE, XÓA CODE, CHỈNH CODE thì ta phải vào menu Tools\Macro\Security, chuyển sang tab Trusted Publishers và check vào "Trust access... " mới dùng được
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Tuy chưa làm thử nhưng tôi có hướng như sau:
1. Để nguyên Function Compare2List(ByVal sArray1, ByVal sArray2, ByVal CompareMod As Long)
2. Dùng 1 sub main duy nhất, trong đó:
a. Dùng 4 inputbox để nhập:​

  • Vùng DL1
  • Vùng DL2
  • CompareMod
  • Vị trí cần dán kết quả
b. Chạy code: (đại khái)
PHP:
sArray1 = Inputbox1
sArray2 = Inputbox2
CompareMod = Inputbox3
Dich = Inputbox4
ArrKQ = Compare2List(sArray1, sArray2, CompareMod)
Dich.Resize(...) = ArrKQ
Vì nhận thấy cách xử lý như haonlh vẫn phải gõ 2 vùng cần so sánh xuống 1 ô nào đó, và khả năng gõ sai là hiển nhiên.
 
Upvote 0
Đã làm xong:
PHP:
Sub Main()
  Dim sArray1, sArray2, Arr, TG As Double, Destination As Range, CompareMod As Long
  sArray1 = Application.InputBox("Select List 1", "List 1", , , , , , 8)
  sArray2 = Application.InputBox("Select list 2", "List 2", , , , , , 8)
  CompareMod = Application.InputBox("Select how to compare:" & Chr(10) & _
  "1: Available in 2 lists" & Chr(10) & _
  "2: Available in List 1, Not available in list 2" & Chr(10) & _
  "3: Available in List 2, Not available in list 1", "Select one", , , , , 1)
  Set Destination = Application.InputBox("Copy to:", "Select destination", , , , , , 8)
  TG = Timer
  
Arr = Compare2List(sArray1, sArray2, CompareMod)
Destination.Resize(UBound(Arr, 1)).Value = Arr
  MsgBox Timer - TG
End Sub
Tiện lợi:
- Có thể dùng chuột chọn 2 list ở 2 nơi khác nhau
- Đọc hướng dẫn sử dụng tham số CompareMod trước khi nhập, khỏi sợ quên hoặc nhầm
- Có thể dùng chuột chọn vị trí cần dán kết quả.
- 2 Lists và nơi dán kết quả có thể khác sheet.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi nghĩ thế này:

Bài của anhtuan là 1 demo. Khi dùng, ta chép dữ liệu vào 2 cột A, B của Sheet của file của anhtuan cấp. Thế là xong. Và cần kết quả nào thì chép về.

Cách của tôi là để không phải chép dữ liệu đi và về. Tất nhiên phải mở sẵn file của anhtuan lên. 3 tham số của đầu cột kết quả là giống như 1 tiêu đề gợi nhớ đến ý nghĩa của kết quả.

Tôi cho rằng cách của ptm0412 là cũng tốt. Nhưng giao tiếp với nhiều hộp thoại thì nhiều khi cảm thấy chậm. Nếu anh sửa lại chỉ cần 1 hộp thoại mà có cả các tham số thì tốt hơn.

Như vậy tuỳ ý thích, sự cảm nhận thuận tiện mà người dùng sử dụng.

Còn ý của anh ndu là đưa cả tên macro vào ô (có phải không anh?). Mục này chưa dám đọc kỹ (dạo này đang bận quá). Xin lỗi.
 
Upvote 0
Tôi nghĩ thế này:

Tôi cho rằng cách của ptm0412 là cũng tốt. Nhưng giao tiếp với nhiều hộp thoại thì nhiều khi cảm thấy chậm. Nếu anh sửa lại chỉ cần 1 hộp thoại mà có cả các tham số thì tốt hơn.
Thời gian giao tiếp nhiều hộp thoại so với thời gian gõ địa chỉ vùng vào 1 cell nào đó chưa biết cái nào chậm hơn.
Tôi làm theo ý tưởng của tôi và theo cách mà tôi cho là tạo thuận tiện cho người dùng.
Tất nhiên là cũng sẽ có người có ý kiến khác và cho rằng như vậy là bất tiện.

Nếu muốn sửa thành 1 hộp thoại duy nhất thì được ngay: Tạo 1 Userform 4 ô nhập liệu, 1 số label ghi chú này nọ, 2 command button, là xong.
 
Upvote 0
Tôi nghĩ thế này:

Bài của anhtuan là 1 demo. Khi dùng, ta chép dữ liệu vào 2 cột A, B của Sheet của file của anhtuan cấp. Thế là xong.
Bạn đâu có nhất thiết phải chép dữ liệu vào cột A, B chứ ---> Cái Sub Main ấy, bạn sửa thế nào là tùy ý, miễn sao phù hợp với dữ liệu thật của bạn thì thôi
Tôi lấy ví dụ công cụ Advanced Filter của Excel. Nó là thứ có sẳn, tuy nhiên khi dùng thì bạn vẫn phải tự mình chọn vùng, check các tùy chọn bằng tay cơ mà
 
Upvote 0
Nguyên văn bởi ptm0412
Tiện lợi:
- Đọc hướng dẫn sử dụng tham số CompareMod trước khi nhập, khỏi sợ quên hoặc nhầm
Có thể sửa lại như thế này không anh:
- Đọc hướng dẫn sử dụng tham số CompareMod trước khi Doubleclick để nhận tham số. Cám ơn
 
Upvote 0
Tâm đang nói double click vào đâu? file nào? của ai?

Code của ptm khi chạy nó ra cái này để nhập nè:

CompareMode.jpg
 
Upvote 0
Tâm đang nói double click vào đâu? file nào? của ai?

Code của ptm khi chạy nó ra cái này để nhập nè:

View attachment 62339
---
Em xin lỗi,vì em diển đạt không hết ý, ý em muốn tiện lợi là ra luôn 1 bảng khác na ná như bảng trên nhưng có thể double click để truyền không cần phải nhập bằng tay nữa đó anh ( giống như Listbox trong userform vậy).
* Cho em thời gian test
 
Lần chỉnh sửa cuối:
Upvote 0
Chọn 1 trong 3 cái hiển thị, khỏi gõ, đó là Listbox hoặc combobox, thế là phải tạo form rồi:

3 cái RefEdit
1 cái Combobox
2 CommandButton

Code của Command Button:

PHP:
Private Sub Extract_Click()
On Error GoTo Loi1
Dim sArray1, sArray2, Arr, TG As Double, Destination As Range, CompareMode As Long
  sArray1 = Range(REdit1).Value
  sArray2 = Range(REdit2).Value
  CompareMode = Val(Cbbox1)
  Set Destination = Range(REdit3)
  
  TG = Timer
Arr = Compare2List(sArray1, sArray2, CompareMode)
Destination.Resize(UBound(Arr, 1)).Value = Arr
  msgbox Timer - TG
  Unload Me: Exit Sub
Loi1:
msgbox "Try again, or hit cancel!"
Exit Sub
End Sub

*test xong chưa không biết, đành đoạn ra đi, không nhấn tks 1 cái!
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Chọn 1 trong 3 cái hiển thị, khỏi gõ, đó là Listbox hoặc combobox, thế là phải tạo form rồi:

3 cái RefEdit
1 cái Combobox
2 CommandButton

Code của Command Button:

PHP:
Private Sub Extract_Click()
On Error GoTo Loi1
Dim sArray1, sArray2, Arr, TG As Double, Destination As Range, CompareMode As Long
  sArray1 = Range(REdit1).Value
  sArray2 = Range(REdit2).Value
  CompareMode = Val(Cbbox1)
  Set Destination = Range(REdit3)
  
  TG = Timer
Arr = Compare2List(sArray1, sArray2, CompareMode)
Destination.Resize(UBound(Arr, 1)).Value = Arr
  msgbox Timer - TG
  Unload Me: Exit Sub
Loi1:
msgbox "Try again, or hit cancel!"
Exit Sub
End Sub

*test xong chưa không biết, đành đoạn ra đi, không nhấn tks 1 cái!
Cái chổ CompareMod em nghĩ sư phụ cho vào 3 cái OptionButton (OptionButton đặt trong 1 Frame) sẽ hay hơn ---> Khởi động UserForm thì mặc định sẽ check sẳn 1 cái. Khi người dùng xài, chắc chắn 1 trong 3 OptionButton này đã được check <===> CompareMod sẽ là 1 hoặc 2 hoặc 3, khỏi sợ người ta gõ bừa
 
Upvote 0
Chỉ cần có ý tưởng khả thi là làm được thôi. Code cho Option Button cũng dễ, không khó gì đâu, Tâm làm dư sức.
Hay là Tam8678 làm 1 phát biểu diễn đi?
 
Lần chỉnh sửa cuối:
Upvote 0
Chọn 1 trong 3 cái hiển thị, khỏi gõ, đó là Listbox hoặc combobox, thế là phải tạo form rồi:

3 cái RefEdit
1 cái Combobox
2 CommandButton

Code của Command Button:

PHP:
Private Sub Extract_Click()
On Error GoTo Loi1
Dim sArray1, sArray2, Arr, TG As Double, Destination As Range, CompareMode As Long
sArray1 = Range(REdit1).Value
sArray2 = Range(REdit2).Value
CompareMode = Val(Cbbox1)
Set Destination = Range(REdit3)
 
TG = Timer
Arr = Compare2List(sArray1, sArray2, CompareMode)
Destination.Resize(UBound(Arr, 1)).Value = Arr
msgbox Timer - TG
Unload Me: Exit Sub
Loi1:
msgbox "Try again, or hit cancel!"
Exit Sub
End Sub

*test xong chưa không biết, đành đoạn ra đi, không nhấn tks 1 cái!
---
Đáng nể ( thêm chút nữa thì thêm dấu- thêm rồi). Trong trường hợp 2 list giống nhau, thì khi chọn điều kiện 2 hoặc 3 thì có nên ra 1 thông báo là không tìm thấy không anh? (Em viết thì không nổi nhưng đòi hỏi "tiện lợi" thì hay lắm %#^#$).
*Ý code cho option Button là của ndu
** Buộc lòng phải thêm dấu thôi __--__
 
Lần chỉnh sửa cuối:
Upvote 0
Như vầy không biết đã được chưa?
Ngày xưa làm cái trúc xanh, có 1 tên chotter (chọt sĩ), chọt hết cái này đến cái khác, nhờ vậy mà hoàn thiện.
Lần này cũng lại phải cám ơn chọt sĩ nữa rồi.

CompareForm.gif
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Cám ơn Bác, hay quá. Nhưng cho em xin PM để giải nén file trên.
Gì mà PM trời? File RAR thôi mà
Giải nén luôn cho bác đây
Lưu ý thêm:
- Trong hàm Compare2List có đoạn:
PHP:
ub = IIf(Dic1.Count > Dic2.Count, Dic1.Count, Dic2.Count)
- Nên thêm như vầy mới chắc:
PHP:
ub = IIf(Dic1.Count > Dic2.Count, Dic1.Count, Dic2.Count)
Ìf ub = 0 then ub = 1
Tránh trường hợp ub = 0 vì vùng dữ liệu rổng
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Gì mà PM trời? File RAR thôi mà
Giải nén luôn cho bác đây
Thú thật, chả biết thế nào mà down về mấy lần mà giải nén không được. Kg biết file trên bị lỗi hay là máy mình bị lỗi. Các file rar khác vẫn unzip OK.
Cám ơn Bác.
File ex bị gì mà mở ra thì như sau.
 

File đính kèm

  • LoiGPE.JPG
    LoiGPE.JPG
    113.2 KB · Đọc: 146
Lần chỉnh sửa cuối:
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
---
Không hiểu vì sao, mở file của chú lên, run code thì .....treo luôn
Uh nhỉ! Chẳng hiểu sao lại vậy. Em chỉ giải nén file của sư phụ, xóa bớt dòng (giảm dung lượng) nhưng giờ kiểm tra lại thấy mất tiêu mấy cái module
Em upload lại rồi đấy, anh kiểm tra thử xem
 
Upvote 0
- Nên thêm như vầy mới chắc:
ub = IIf(Dic1.Count > Dic2.Count, Dic1.Count, Dic2.Count)
Ìf ub = 0 then ub = 1

Tránh trường hợp ub = 0 vì vùng dữ liệu rổng

ub = 0 khi và chỉ khi Dic1.Count = 0 và Dic2.Count = 0
nghĩa là cả 2 vùng DL1 và DL2 rỗng (có chọn, nhưng chọn vùng trắng trơn). Còn 1 trong 2 vùng chọn có ít nhất 1 ô dữ liệu thì không lỗi. Chọn 2 vùng trắng trơn để trích lọc thì chỉ có điên mới làm.

Nếu nói về bẫy lỗi: dùng form như trên thì đã bẫy lỗi rồi, bắt làm lại. Không lo. Tuy nhiên, cẩn tắc vô iu, khà khà.
 
Upvote 0
Chọn 2 vùng trắng trơn để trích lọc thì chỉ có điên mới làm.
Đôi lúc cũng có đấy sư phụ à! Chẳng biết được
Ẹc... Ẹc...
---------------
Ah, còn cái vụ chạy code bị treo máy như anh Tâm nói ở trên bây giờ em mới phát hiện: Thì ra file của sư phụ, trong References có 1 thằng bị MISSING...
 
Lần chỉnh sửa cuối:
Upvote 0
Không ai chọt thêm, thì tự mình chọt mình vậy:

Thêm 1 option nữa: gộp từ 2 danh sách ra 1 danh sách duy nhất (không trùng)
hì hì, select thêm 1 case trong module, thêm 1 OptionButton trên form. Cò già làm thử nha, vô dòm không à! Thu Nghi thì tha, hư mạng rồi!
 
Lần chỉnh sửa cuối:
Upvote 0
1.Thêm 1 Option button: Quá dễ
2.Thêm 1 case trong function: Suy luận 1 tí, copy 1 số câu code ở trên trên paste xuống dưới là ok.
3.Code cho Option 4: Hơi rắc rối:
Do gộp từ 2 DS nên phải bẫy trường hợp DS kết quả vượt quá số dòng của anh Bill:
- Tính số dòng còn lại từ Destination trở xuống vô biến RowLeft
- Tính số giá trị <> "" có trong Arr vô biến ArrCount
- So sánh RowLeft và ArrCount
- Nếu ArrCount < RowLeft thì gán Arr xuống bình thường
- Ngược lại, hỏi xem muốn chia ra bao nhiêu cột
- Biến đổi Arr từ 1 cột thành nhiều cột
- Gán kết quả nhiều cột xuống.



Trích code Form:
PHP:
Arr = Compare2List(sArray1, sArray2, CompareMode)
RowLeft = ActiveSheet.Rows.Count - Destination.Row
If Arr(1, 1) <> "" Then
    If ArrCount < RowLeft Then
        Destination.Resize(UBound(Arr, 1)).Value = Arr
    Else
        Col = Application.InputBox("Your new list is too long, there aren't enough rows to place it," & _
        Chr(10) & "How many columns do you want to separate it to?", "Separate to columns", , , , , , 1)
        ReDim ArrKQ(1 To ArrCount / Col + 1, 1 To Col)
            j = 1: k = 1
        For i = 1 To ArrCount
            ArrKQ(j, k) = Arr(i, 1)
            j = j + 1
            If j > ArrCount / Col + 1 Then j = 1: k = k + 1
        Next
        Destination.Resize(ArrCount / Col + 1, Col).Value = ArrKQ
    End If
Else
    msgbox "No records to be extracted!", , "Nothing matched"
End If
Code Module:
PHP:
    Case 4
      ub = Dic1.Count + Dic2.Count
      ReDim Arr(1 To ub, 1 To 1)
      For Each Item In TmpKeys1
          j = j + 1
          Arr(j, 1) = CStr(Item)
      Next
      For Each Item In TmpKeys2
        If Not Dic1.Exists(CStr(Item)) Then
          j = j + 1
          Arr(j, 1) = CStr(Item)
        End If
      Next
  End Select
  ArrCount = j
Tải file tại đây

(thử với option 4 và với 2 cột, mỗi cột nhiều ngàn dòng sao cho kết quả nhiều hơn 65.536 dòng)
 
Lần chỉnh sửa cuối:
Upvote 0
Lỗi gì trời? Tâm xem có [MISSING] gì không? (thấy ndu bảo vậy)
Cụ thể là báo lỗi thế nào chứ?
Hic, lấy được 1 cái dấu hỏi cho chữ "nê" cũng khó khăn, lấy 1 cái thank cũng khó khăn quá đi. Tâm có xài teamviewer không? Cài teamviewer rồi add nick YM! thanhmy_pham đi.
 
Upvote 0
Lỗi gì trời? Tâm xem có [MISSING] gì không? (thấy ndu bảo vậy)
Cụ thể là báo lỗi thế nào chứ?
Hic, lấy được 1 cái dấu hỏi cho chữ "nê" cũng khó khăn, lấy 1 cái thank cũng khó khăn quá đi. Tâm có xài teamviewer không? Cài teamviewer rồi add nick YM! thanhmy_pham đi.
---
Do những bài trước file của anh, em xem không có lỗi này, nhưng file này thì đúng là tại [MISSING]. Xin lỗi anh nhé, anh lúc nào cũng ĐÁNG NÊ @#!^%.
Anh cho em hỏi trường hợp lúc có, lúc không [MISSING] là vì sao ?
*Em đi làm đây.
 
Upvote 0
2.Thêm 1 case trong function: Suy luận 1 tí, copy 1 số câu code ở trên trên paste xuống dưới là ok.
Em nghĩ vầy: Hàm Compare2List và Unique làm 2 chuyện khác nhau. Do đó nên viết Unique thành 1 hàm riêng biệt chứ không nên cho 1 hàm ôm đồm quá nhiều việc. Và cái Opt4 cứ việc liên kết đến nó là xong
 
Upvote 0
Thì sẵn đã khai báo cả chục biến, đã tạo được 2 Dic, thì cứ thế phang tiếp, chứ tội gì. Khà khà khà
 
Upvote 0
Vậy ndu sửa, khà khà
Mình tính là hoàn thiện cái này xong, ai cần sử dụng thường xuyên thì lưu lại như 1 add-in mà dùng. 1 hay 2 Function tuỳ theo thế nào là tối ưu, chứ không phải vì "lạc quẻ". Mà nói chung, cũng đều là "trích xuất dữ liệu từ 2 danh sách"
Tại tiêu đề đã lỡ đặt là "so sánh 2 danh sách" thôi.
 
Upvote 0
Đây! Em gữi cái GetUnique này lên, ai xài thì xài:
PHP:
Function GetUnique(ParamArray sArray())
  Dim SubArr, Item
  With CreateObject("Scripting.Dictionary")
    For Each SubArr In sArray
      For Each Item In SubArr
        If CStr(Item) <> "" Then
          If Not .Exists(CStr(Item)) Then .Add CStr(Item), ""
        End If
      Next
    Next
    GetUnique = IIf(.Count = 0, "", .Keys)
  End With
End Function
Cái này không phải là lấy Unique 2 danh sách. Bao nhiêu danh sách và bất kể danh sách cùng sheet hay khác sheet cũng xơi tuốt! Thậm chí là lấy Unique list từ 1 kết quả của 1 công thức mảng trả về...
 
Lần chỉnh sửa cuối:
Upvote 0
Vậy cái Unique này phải làm riêng rồi

Đại khái là làm 1 form gồm:
- 1 RefEdit, lấy vùng cần tính (lấy nhiều lần)
- 1 Listbox
- 1 nút Add, khi nhấn sẽ add vùng từ RefEdit vào Listbox, xoá trắng RefEdit trên, chọn tiếp vùng khác
- 1 nút Delete, để xoá bớt 1 vùng đã Add, nếu muốn
- 1 nút nhấn DO, lụm hết mấy vùng đã Add trong listbox, đưa vào Function
- 1 RefEdit khác để lấy destination
- 1 nút cancel

Không dễ!
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn bác Anhtuan1066 nhé, Chủ đề của bác rất hay, nhờ nó chiều nay tôi tiếp thu thêm khá nhiều kiến thức bổ ích.
 
Upvote 0
File của các bác rất hay, nhưng em gặp vấn đề là nếu so sánh 2 mảng ở workbook khác thì không được.
Với lại có cách nào khi chọn mảng, dùng được tổ hợp phím "CTRL+SHIFT+mũi tên" không?
Ngoài ra mỗi khi thực hiện lệnh xong, bảng lại tắt đi, kể ra nó chỉ tắt khi nào mình nhấn nút X thì hay hơn nhỉ?
Em ko rành về vba, làm sao được các bác!
 
Lần chỉnh sửa cuối:
Upvote 0
Ẹc, chưa có bác nào tham gia tiếp. Chờ thêm tí nữa. Hic!!!
 
Upvote 0
Em lên nhờ các bác được không?... e gửi file Excel cho các bác so và trích sang cột C cho em
Những bài A có mà B không có thì cho sang C
Em dò cái danh sách bài hát mà không phải dân chuyên kế toán nên khó khăn trong việc này quá
Mong cả nhà giúp em nhé...
Thanks các bác nhiều :)
 

File đính kèm

Upvote 0
Em lên nhờ các bác được không?... e gửi file Excel cho các bác so và trích sang cột C cho em
Những bài A có mà B không có thì cho sang C
Em dò cái danh sách bài hát mà không phải dân chuyên kế toán nên khó khăn trong việc này quá
Mong cả nhà giúp em nhé...
Thanks các bác nhiều :)

Của bác đây. Những bài có ở cột A mà không ở B sẽ được ghi ra cột C. Cột D đếm xem các bài đó có ở trong cột B không để kiểm tra lại.

Mã:
Sub test()
    Application.ScreenUpdating = False
        
        Dim t As Date
        Dim colA As Variant, colB As Variant
        Dim x, y, match As Boolean
        t = Now
        
        colA = Range("A1:A" & Range("A" & Rows.Count).End(3).Row).Value
        colB = Range("B1:B" & Range("B" & Rows.Count).End(3).Row).Value
        
        For Each x In colA
            match = False
            For Each y In colB
                If x = y Then match = True
            Next y
            If Not match Then
                Range("C" & Range("C" & Rows.Count).End(3).Row + 1) = x
            End If
        Next x
    
        msgbox "Done in " & DateDiff("s", t, Now) & " s"
    Application.ScreenUpdating = True
End Sub

hoặc thử cái này (nhanh hơn)

Mã:
Sub HTH()
    Dim t As Double
    t = Timer
    Application.ScreenUpdating = False


    With Range("A1", Cells(Rows.Count, "A").End(xlUp)).Offset(, 7)
        .Formula = "=VLOOKUP(A1,B:B,1,FALSE)"
        .Value2 = .Value2
        .SpecialCells(xlCellTypeConstants, 16).Offset(, -7).Copy Range("C" & Rows.Count).End(xlUp).Offset(1)
        .ClearContents
    End With


    Application.ScreenUpdating = True
    MsgBox Timer - t
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom