Dùng Dictionary để lọc dữ liệu

Liên hệ QC

FPT_online

Thành viên hoạt động
Tham gia
27/10/13
Bài viết
133
Được thích
16
Mọi người cho em hỏi em muốn dùng dictionary để lọc các mã không trùng từ sheet khác, em có ghi trong vd rồi mong mọi người chỉ giúp
 

File đính kèm

Đây chỉ là ví dụ để em hiểu thêm về Dictionary thôi ạ, nên em muốn hỏi nếu làm thì sẽ làm như thế nào đó ạ
Bước 1> Dùng vòng lập nạp dữ liệu sheet1 vào Dictionary, với key là giá trị nối chuỗi từ cột B và C <--- Có được từ điển
Bước 2> Dùng vòng lập duyệt dữ liệu ở sheet2, cũng nối chuỗi cột B và C lại rồi mang đi tra vào từ điển, nếu chưa có thì thêm vào
Đại khái vậy
 
Upvote 0
Bước 1> Dùng vòng lập nạp dữ liệu sheet1 vào Dictionary, với key là giá trị nối chuỗi từ cột B và C <--- Có được từ điển
Bước 2> Dùng vòng lập duyệt dữ liệu ở sheet2, cũng nối chuỗi cột B và C lại rồi mang đi tra vào từ điển, nếu chưa có thì thêm vào
Đại khái vậy
Vâng để em làm thử
 
Upvote 0
Mọi người cho em hỏi em muốn dùng dictionary để lọc các mã không trùng từ sheet khác, em có ghi trong vd rồi mong mọi người chỉ giúp

Lâu rồi không viết code, bạn test thử xem ntn
Mã:
Sub gpe()
Dim Arr_sheet1, Arr_sheet2
Dim i&, tmp, sResult$
    Arr_sheet2 = Sheet2.Range("A1").CurrentRegion
    Arr_sheet1 = Sheet1.Range("A1").CurrentRegion
    With CreateObject("Scripting.dictionary")
        For i = 1 To UBound(Arr_sheet2, 1)
            tmp = Arr_sheet2(i, 2) & Chr(0) & Arr_sheet2(i, 3)
            If Len(tmp) Then If Not .Exists(tmp) Then .Add tmp, ""
        Next
        For i = 1 To UBound(Arr_sheet1, 1)
            tmp = Arr_sheet1(i, 2) & Chr(0) & Arr_sheet1(i, 3)
            If Len(tmp) Then If Not .Exists(tmp) Then sResult = sResult & Replace(tmp, Chr(0), vbTab) & vbCrLf
        Next
    End With
    If Len(sResult) Then MsgBox sResult
End Sub
 
Upvote 0
Lâu rồi không viết code, bạn test thử xem ntn
Mã:
Sub gpe()
Dim Arr_sheet1, Arr_sheet2
Dim i&, tmp, sResult$
    Arr_sheet2 = Sheet2.Range("A1").CurrentRegion
    Arr_sheet1 = Sheet1.Range("A1").CurrentRegion
    With CreateObject("Scripting.dictionary")
        For i = 1 To UBound(Arr_sheet2, 1)
            tmp = Arr_sheet2(i, 2) & Chr(0) & Arr_sheet2(i, 3)
            If Len(tmp) Then If Not .Exists(tmp) Then .Add tmp, ""
        Next
        For i = 1 To UBound(Arr_sheet1, 1)
            tmp = Arr_sheet1(i, 2) & Chr(0) & Arr_sheet1(i, 3)
            If Len(tmp) Then If Not .Exists(tmp) Then sResult = sResult & Replace(tmp, Chr(0), vbTab) & vbCrLf
        Next
    End With
    If Len(sResult) Then MsgBox sResult
End Sub
Cái này mình chạy thử thấy kết quả ra chưa đủ
 
Upvote 0
Bước 1> Dùng vòng lập nạp dữ liệu sheet1 vào Dictionary, với key là giá trị nối chuỗi từ cột B và C <--- Có được từ điển
Bước 2> Dùng vòng lập duyệt dữ liệu ở sheet2, cũng nối chuỗi cột B và C lại rồi mang đi tra vào từ điển, nếu chưa có thì thêm vào
Đại khái vậy
Mã:
Sub loc()
Dim dic As Object
Dim arr(), rng(), rng2(), itemp As String, itemp1 As String
Dim lr As Long, lr2 As Long, i As Long, j As Long, k As Long
Set dic = CreateObject("Scripting.dictionary")
With Sheet1
lr = .Range("B" & Rows.Count).End(xlUp).Row
rng = .Range("B2:D" & lr)
End With
With Sheet2
lr2 = .Range("B" & Rows.Count).End(xlUp).Row
rng2 = .Range("B2:D" & lr2)
End With
ReDim arr(1 To UBound(rng, 1), 1 To 4)
For i = 1 To UBound(rng, 1)
    itemp = rng(i, 1)
    If itemp <> "" And Not dic.Exists(itemp) Then
        k = k + 1
        dic.Add itemp, k
        arr(k, 2) = rng(i, 1)
    End If
Next i
For i = 1 To UBound(rng2, 1)
    itemp1 = rng2(i, 1)
    If itemp1 <> "" And Not dic.Exists(itemp) Then
        j = j + 1
        dic.Add itemp, j
        arr(j, 2) = rng2(i, 1)
    End If
Next i
With Sheet3
.Range("A2").Resize(k + j, 4) = arr
End With
End Sub
Em làm tới đây thì vướng không biết làm sao nữa ạ
 
Upvote 0
Bài #8:
- Bạn chỉ lấy dữ liệu ở cột B nên chỉ cần xét cột B thôi, không cânf xét B2: D & lr.
Chỗ này cần bẫy lỗi gán range vào array khi chỉ có 1 cell (lr=2), và khi lr<2 (không có dữ liệu).
- Do hai vòng lặp độc lập nên có thể dùng lại biến itemp (không cần thêm biến itemp2).
- Xét itemp khác rỗng thì ngắt riêng rồi mới xét có trong dic hay không, tức là không nên dùng And. Có thể đặt tên biến là sKey chẳng hạn.
Mã:
if len(sKey)>0 then
If dic.exists(sKey)=false then
- Ở vòng lặp thứ hai, bạn muốn lấy tiếp kết quả vào mảng arr thì thay j=j+1 bằng k=k+1.
- Gán kết quả xuống sheet phải kiểm tra có kết quả có hay không (k>0), nếu không sẽ lỗi ở resize(rows, columns) với rows và columns luôn >0.
 
Upvote 0
Bài #8:
- Bạn chỉ lấy dữ liệu ở cột B nên chỉ cần xét cột B thôi, không cânf xét B2: D & lr.
Chỗ này cần bẫy lỗi gán range vào array khi chỉ có 1 cell (lr=2), và khi lr<2 (không có dữ liệu).
- Do hai vòng lặp độc lập nên có thể dùng lại biến itemp (không cần thêm biến itemp2).
- Xét itemp khác rỗng thì ngắt riêng rồi mới xét có trong dic hay không, tức là không nên dùng And. Có thể đặt tên biến là sKey chẳng hạn.
Mã:
if len(sKey)>0 then
If dic.exists(sKey)=false then
- Ở vòng lặp thứ hai, bạn muốn lấy tiếp kết quả vào mảng arr thì thay j=j+1 bằng k=k+1.
- Gán kết quả xuống sheet phải kiểm tra có kết quả có hay không (k>0), nếu không sẽ lỗi ở resize(rows, columns) với rows và columns luôn >0.
Mình vẫn chưa hiểu rõ mong bạn sửa code luôn để mình học hỏi với
 
Upvote 0
Mình vẫn chưa hiểu rõ mong bạn sửa code luôn để mình học hỏi với
. Bạn cần đọc thêm lý thuyết về array rồi mới đọc tiếp bài Dictionary. Bạn tìm chủ để của mình viết mà đọc, hai bài đó khá chi tiết, có cả một số chỗ lưu ý quan trọng.
 
Upvote 0
. Bạn cần đọc thêm lý thuyết về array rồi mới đọc tiếp bài Dictionary. Bạn tìm chủ để của mình viết mà đọc, hai bài đó khá chi tiết, có cả một số chỗ lưu ý quan trọng.
Bạn nói như vậy ngừoi mới vào đây sẽ hiểu lầm là Dictionary có liên quan đến mảng.
Trên thực tế, nó đâu có liên quan đến mảng. Dữ liệu của Dic gần với Collection hơn Array.
Giải thích đúng thì phải như vầy:
Cách viết code thường gặp ở diễn đàn này là khi tính toán thì ghi dữ liệu vào một mảng. Sau khi tính xong thì ghi mảng xuống sheet. Vì vậy, thớt nên tìm hiểu thêm về mảng trước khi tiếp tục học code ở đây.
 
Upvote 0
Mã:
Sub loc()
Dim lr As Long, rng(), arr(1 To 1000, 1 To 4), dic As Object, tmp As String, k As Long, i As Long
With Sheet1
lr = .Range("B" & Rows.Count).End(xlUp).Row
rng = .Range("B2:D" & lr)
End With
With Sheet2
lr2 = .Range("B" & Rows.Count).End(xlUp).Row
rng2 = .Range("B2:D" & lr)
Set dic = CreateObject("Scripting.dictionary")
For i = 1 To UBound(rng, 1)
 tmp = rng(i, 1) & rng(i, 2)
    If tmp <> "" And Not dic.Exists(tmp) Then
        k = k + 1
        dic.Add tmp, k
        arr(k, 1) = k
        arr(k, 2) = rng(i, 1)
        arr(k, 3) = rng(i, 2)
    End If
Next i
For i = 1 To UBound(rng2, 1)
 tmp = rng2(i, 1) & rng2(i, 2)
    If tmp <> "" And Not dic.Exists(tmp) Then
        k = k + 1
        dic.Add tmp, k
        arr(k, 1) = k
        arr(k, 2) = rng2(i, 1)
        arr(k, 3) = rng2(i, 2)
    End If
Next i
End With
With Sheet3
.Range("A3").Resize(k, 3) = arr
End With
End Sub
Với bài này em viết như này thì đã ra đúng kết quả, nhưng mọi người cho em hỏi có cách viết nào ngắn gọn hơn không ạ, Em cám ơn
 
Upvote 0
Mã:
Sub loc()
Dim lr As Long, rng(), arr(1 To 1000, 1 To 4), dic As Object, tmp As String, k As Long, i As Long
With Sheet1
lr = .Range("B" & Rows.Count).End(xlUp).Row
rng = .Range("B2:D" & lr)
End With
With Sheet2
lr2 = .Range("B" & Rows.Count).End(xlUp).Row
rng2 = .Range("B2:D" & lr)
Set dic = CreateObject("Scripting.dictionary")
For i = 1 To UBound(rng, 1)
tmp = rng(i, 1) & rng(i, 2)
    If tmp <> "" And Not dic.Exists(tmp) Then
        k = k + 1
        dic.Add tmp, k
        arr(k, 1) = k
        arr(k, 2) = rng(i, 1)
        arr(k, 3) = rng(i, 2)
    End If
Next i
For i = 1 To UBound(rng2, 1)
tmp = rng2(i, 1) & rng2(i, 2)
    If tmp <> "" And Not dic.Exists(tmp) Then
        k = k + 1
        dic.Add tmp, k
        arr(k, 1) = k
        arr(k, 2) = rng2(i, 1)
        arr(k, 3) = rng2(i, 2)
    End If
Next i
End With
With Sheet3
.Range("A3").Resize(k, 3) = arr
End With
End Sub
Với bài này em viết như này thì đã ra đúng kết quả, nhưng mọi người cho em hỏi có cách viết nào ngắn gọn hơn không ạ, Em cám ơn
Chưa đúng, bạn còn nhầm chỗ này:
Mã:
lr2 = .Range("B" & Rows.Count).End(xlUp).Row
rng2 = .Range("B2:D" & lr)
phải là lr2
Dạng bài này phải viết thế, muốn ngắn nữa thì viết 1 vòng FOR thôi, nếu số dòng 2 bảng bằng nhau (khẳng định) thì nhẹ nhàng, nếu khác thì hơi....linh tinh, nói chung cũng chẳng ngắn bi nhiêu (chỉ có nhìn thấy 1 vòng FOR cho nó có vẻ "zồ" một tý tẹo. Híc)
Thân
 
Upvote 0
Chưa đúng, bạn còn nhầm chỗ này:
Mã:
lr2 = .Range("B" & Rows.Count).End(xlUp).Row
rng2 = .Range("B2:D" & lr)
phải là lr2
Dạng bài này phải viết thế, muốn ngắn nữa thì viết 1 vòng FOR thôi, nếu số dòng 2 bảng bằng nhau (khẳng định) thì nhẹ nhàng, nếu khác thì hơi....linh tinh, nói chung cũng chẳng ngắn bi nhiêu (chỉ có nhìn thấy 1 vòng FOR cho nó có vẻ "zồ" một tý tẹo. Híc)
Thân
Vâng, số dòng 2 bảng linh động khác nhau anh ạ, anh chỉ em cách viết với 1 vòng lặp For với. em đang cần để học hỏi
 
Upvote 0
Vâng, số dòng 2 bảng linh động khác nhau anh ạ, anh chỉ em cách viết với 1 vòng lặp For với. em đang cần để học hỏi
Viết 1 vòng chơi vui thôi, chứ chẳng rút bao nhiêu
Cẩn thận với việc ghép dữ liệu rồi so sánh, khi không nắm chắc dạng dữ liệu nên chèn 1 "thằng em" hơi "là lạ" vào giữa tụi nó cho chắc cú
Thân
Mã:
Public Sub TeoTeo()
    Dim Vung1, Vung2, Imax, I, K, Kq, Dic, Tam1, Tam2
    Set Dic = CreateObject("Scripting.dictionary")
    Vung1 = Sheets("sheet1").Range(Sheets("sheet1").[B2], Sheets("sheet1").[B5000].End(xlUp)).Resize(, 2)
    Vung2 = Sheets("sheet2").Range(Sheets("sheet2").[B2], Sheets("sheet2").[B5000].End(xlUp)).Resize(, 2)
    Imax = IIf(UBound(Vung1) >= UBound(Vung2), UBound(Vung1), UBound(Vung2))
    ReDim Kq(1 To UBound(Vung1) + UBound(Vung2), 1 To 3)
        For I = 1 To Imax
            If I <= UBound(Vung1) Then
                If Vung1(I, 1) <> "" Then
                    Tam1 = Vung1(I, 1) & "@" & Vung1(I, 2)
                    If Not Dic.Exists(Tam1) Then
                        K = K + 1
                        Dic.Add Tam1, K
                        Kq(K, 1) = K: Kq(K, 2) = Vung1(I, 1): Kq(K, 3) = Vung1(I, 2)
                    End If
                End If
            End If
                If I <= UBound(Vung2) Then
                    If Vung2(I, 1) <> "" Then
                        Tam2 = Vung2(I, 1) & "@" & Vung2(I, 2)
                        If Not Dic.Exists(Tam2) Then
                            K = K + 1
                            Dic.Add Tam2, K
                            Kq(K, 1) = K: Kq(K, 2) = Vung2(I, 1): Kq(K, 3) = Vung2(I, 2)
                        End If
                End If
            End If
        Next I
    Sheets("sheet3").[E3].Resize(K, 3) = Kq
End Sub
 
Upvote 0
Viết 1 vòng chơi vui thôi, chứ chẳng rút bao nhiêu
Cẩn thận với việc ghép dữ liệu rồi so sánh, khi không nắm chắc dạng dữ liệu nên chèn 1 "thằng em" hơi "là lạ" vào giữa tụi nó cho chắc cú
Thân
Mã:
Public Sub TeoTeo()
    Dim Vung1, Vung2, Imax, I, K, Kq, Dic, Tam1, Tam2
    Set Dic = CreateObject("Scripting.dictionary")
    Vung1 = Sheets("sheet1").Range(Sheets("sheet1").[B2], Sheets("sheet1").[B5000].End(xlUp)).Resize(, 2)
    Vung2 = Sheets("sheet2").Range(Sheets("sheet2").[B2], Sheets("sheet2").[B5000].End(xlUp)).Resize(, 2)
    Imax = IIf(UBound(Vung1) >= UBound(Vung2), UBound(Vung1), UBound(Vung2))
    ReDim Kq(1 To UBound(Vung1) + UBound(Vung2), 1 To 3)
        For I = 1 To Imax
            If I <= UBound(Vung1) Then
                If Vung1(I, 1) <> "" Then
                    Tam1 = Vung1(I, 1) & "@" & Vung1(I, 2)
                    If Not Dic.Exists(Tam1) Then
                        K = K + 1
                        Dic.Add Tam1, K
                        Kq(K, 1) = K: Kq(K, 2) = Vung1(I, 1): Kq(K, 3) = Vung1(I, 2)
                    End If
                End If
            End If
                If I <= UBound(Vung2) Then
                    If Vung2(I, 1) <> "" Then
                        Tam2 = Vung2(I, 1) & "@" & Vung2(I, 2)
                        If Not Dic.Exists(Tam2) Then
                            K = K + 1
                            Dic.Add Tam2, K
                            Kq(K, 1) = K: Kq(K, 2) = Vung2(I, 1): Kq(K, 3) = Vung2(I, 2)
                        End If
                End If
            End If
        Next I
    Sheets("sheet3").[E3].Resize(K, 3) = Kq
End Sub
Dạ, em cảm ơn anh nhiều. Em sẽ xem và học hỏi thêm
 
Upvote 0
Viết 1 vòng chơi vui thôi, chứ chẳng rút bao nhiêu
Cẩn thận với việc ghép dữ liệu rồi so sánh, khi không nắm chắc dạng dữ liệu nên chèn 1 "thằng em" hơi "là lạ" vào giữa tụi nó cho chắc cú
Thân
Mã:
Public Sub TeoTeo()
    Dim Vung1, Vung2, Imax, I, K, Kq, Dic, Tam1, Tam2
    Set Dic = CreateObject("Scripting.dictionary")
    Vung1 = Sheets("sheet1").Range(Sheets("sheet1").[B2], Sheets("sheet1").[B5000].End(xlUp)).Resize(, 2)
    Vung2 = Sheets("sheet2").Range(Sheets("sheet2").[B2], Sheets("sheet2").[B5000].End(xlUp)).Resize(, 2)
    Imax = IIf(UBound(Vung1) >= UBound(Vung2), UBound(Vung1), UBound(Vung2))
    ReDim Kq(1 To UBound(Vung1) + UBound(Vung2), 1 To 3)
        For I = 1 To Imax
            If I <= UBound(Vung1) Then
                If Vung1(I, 1) <> "" Then
                    Tam1 = Vung1(I, 1) & "@" & Vung1(I, 2)
                    If Not Dic.Exists(Tam1) Then
                        K = K + 1
                        Dic.Add Tam1, K
                        Kq(K, 1) = K: Kq(K, 2) = Vung1(I, 1): Kq(K, 3) = Vung1(I, 2)
                    End If
                End If
            End If
                If I <= UBound(Vung2) Then
                    If Vung2(I, 1) <> "" Then
                        Tam2 = Vung2(I, 1) & "@" & Vung2(I, 2)
                        If Not Dic.Exists(Tam2) Then
                            K = K + 1
                            Dic.Add Tam2, K
                            Kq(K, 1) = K: Kq(K, 2) = Vung2(I, 1): Kq(K, 3) = Vung2(I, 2)
                        End If
                End If
            End If
        Next I
    Sheets("sheet3").[E3].Resize(K, 3) = Kq
End Sub

Phần xét vung1 và vung 2 in hệt nhau. Theo đúng lệ code thì ngừoi ta dùng một hàm. Lý do là khi cần chỉnh sửa gì thì chỉ sửa 1 chỗ, không bị sai sót.
Mã:
' trong vòng lặp
            NhetVaoDich Dic, Vung1, Kq, I, K
            NhetVaoDich Dic, Vung2, Kq, I, K
...

Sub NhetVaoDich(byVal Dic As Object, byVal Vung As Variant, byVal Kq As Variant, byVal I As Long, byRef K As Long)
Dim Tam As String
If I > UBound(Vung) Then Exit Sub
                If Vung(I, 1) <> "" Then
                    Tam = Vung(I, 1) & "@" & Vung(I, 2)
                    If Not Dic.Exists(Tam) Then
                        K = K + 1
                        Dic.Add Tam, K
                        Kq(K, 1) = K: Kq(K, 2) = Vung(I, 1): Kq(K, 3) = Vung(I, 2)
                    End If
                End If
End Sub

Tôi giữ code như thế này là giả sử bạn muốn keys của hai vùng chạy xen kẽ nhau. Nếu muốn tất cả keys của vùng 1 nhập trước vùng 2 thì code gọn đẹp hơn nhiều.

Chú: tôi quên mất byVal thì Variant sẽ copy mảng hay chỉ lấy tên mảng (lười viết một mẩu code để thử quá). Nếu nó copy mảng thì hỏng bét
Để chắc ăn, bạn có thể bỏ hết các từ khoá byVal, chỉ giữ lại cái byRef cuối cùng.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom