Cải thiện tốc độ của Dictionary và Vòng lặp

Liên hệ QC

hakhuongdhkt

Gnouhk
Tham gia
26/8/14
Bài viết
42
Được thích
2
Giới tính
Nam
Em chào các bác,

Trước em có nhờ 1 bác trên diễn đàn viết dùm code thay thế cho hàm Vlookup, chạy rất tốt.
Nhưng gần đây do yêu cầu thay đổi, cần phải sửa lại code 1 chút như trong file.

Mục đích: e nhập Sub-Category và Quantity vào sheet "Tim kiem", sau đó chạy code để lấy các thông tin tương ứng (đầu tiên tìm được) với các Sub-Category trong các sheet 2013, 2014, 2015, 2016 mà thỏa mãn điều kiện Quantity lớn hơn Quantity đã nhập tại sheet "Tim kiem".

Tuy nhiên tốc độ chạy rất chậm (do dữ liệu tại các sheet 2013, 2014, 2015, 2016 rất lớn, mỗi sheet ~ 800k dòng).
Các bác xem có thể cải thiện tốc độ bằng cách nào không ạ?
Mong các bác giúp đỡ!
Mã:
Sub Vlookup()
Application.ScreenUpdating = False
Dim arr, data, inputdata, varKey, temvl, dic As Object
Dim i As Long, j As Long, sh As Worksheet, lr As Long
Set dic = CreateObject("scripting.dictionary")
Set shtk = ThisWorkbook.Sheets(1)

lr = shtk.Range("A" & Rows.Count).End(xlUp).Row
shtk.Range("C2:H" & lr).ClearContents
inputdata = shtk.Range("A2:J" & lr).Value
For i = 1 To UBound(inputdata)
    If Not dic.exists(inputdata(i, 1)) Then
        dic.Add inputdata(i, 1), Array(inputdata(i, 2), inputdata(i, 3), inputdata(i, 4), inputdata(i, 5), inputdata(i, 6))
    Else
        temparr = dic(inputdata(i, 1))
        temparr(0) = temparr(0) + inputdata(i, 2)
        dic(inputdata(i, 1)) = temparr
    End If
Next i
For Each varKey In dic.Keys()
    flg = False
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> "Tim kiem" And sh.Name <> "Tru ton" Then
           lr = sh.Range("A" & Rows.Count).End(xlUp).Row
           data = sh.Range("A2:F" & lr).Value
           For i = 1 To UBound(data)
               If varKey = data(i, 1) Then
                    If dic.Item(varKey)(0) <= data(i, 6) Then
                    dic(data(i, 1)) = Array(data(i, 6), data(i, 2), data(i, 3), data(i, 4), data(i, 5))
                    flg = True
                    Exit For
                    End If
               End If
            Next
        End If
        If flg = True Then Exit For
    Next
Next
With shtk
     lr = .Range("A" & Rows.Count).End(xlUp).Row
     If lr = 1 Then Exit Sub
     .Range("C2:H" & lr).ClearContents
     arr = .Range("A2:H" & lr).Value
     For i = 1 To UBound(arr)
         If dic.exists(arr(i, 1)) Then
            arr(i, 3) = dic.Item(arr(i, 1))(1)
            arr(i, 4) = dic.Item(arr(i, 1))(2)
            arr(i, 5) = dic.Item(arr(i, 1))(3)
            arr(i, 6) = dic.Item(arr(i, 1))(4)
            arr(i, 7) = dic.Item(arr(i, 1))(0)
            arr(i, 8) = arr(i, 7) - arr(i, 2)
        End If
    Next i
    .Range("A2:H" & lr).Value = arr
End With

Application.ScreenUpdating = True
End Sub
 

File đính kèm

  • Tim du lieu.xlsb
    1.3 MB · Đọc: 27
Lần chỉnh sửa cuối:
Em chào các bác,

Trước em có nhờ 1 bác trên diễn đàn viết dùm code thay thế cho hàm Vlookup, chạy rất tốt.
Nhưng gần đây do yêu cầu thay đổi, cần phải sửa lại code 1 chút như trong file.

Mục đích: e nhập Sub-Category và Quantity vào sheet "Tim kiem", sau đó chạy code để lấy các thông tin tương ứng (đầu tiên tìm được) với các Sub-Category trong các sheet 2013, 2014, 2015, 2016 mà thỏa mãn điều kiện Quantity lớn hơn Quantity đã nhập tại sheet "Tim kiem".

Tuy nhiên tốc độ chạy rất chậm (do dữ liệu tại các sheet 2013, 2014, 2015, 2016 rất lớn, mỗi sheet ~ 800k dòng).
Các bác xem có thể cải thiện tốc độ bằng cách nào không ạ?
Mong các bác giúp đỡ!
Một cách dùng Power query, bấm refresh dữ liệu khi thêm dữ liệu ở cột A,B
Không biết Ton truoc, Ton sau bạn tính sao, nếu theo cách này thì làm tiếp
 

File đính kèm

  • Tim du lieu.xlsx
    2.2 MB · Đọc: 10
Upvote 0
Một cách dùng Power query, bấm refresh dữ liệu khi thêm dữ liệu ở cột A,B
Không biết Ton truoc, Ton sau bạn tính sao, nếu theo cách này thì làm tiếp
Ton truoc la cột Quantity trong 4 sheet 2013, 2014, 2015, 2016; Còn tồn sau = Ton truoc - Quantity bác ah.
Power Query này lạ lẫm quá =)) nói thật em không biết dùng bác ạ, để em nghiên cứu thêm cách bác làm ra sao.
Với cả em còn một vài Sub nữa liên quan tới cái này nên ưu tiên VBA hơn ạ. Mong bác chỉ giáo!
 
Upvote 0
Ton truoc la cột Quantity trong 4 sheet 2013, 2014, 2015, 2016; Còn tồn sau = Ton truoc - Quantity bác ah.
Power Query này lạ lẫm quá =)) nói thật em không biết dùng bác ạ, để em nghiên cứu thêm cách bác làm ra sao.
Với cả em còn một vài Sub nữa liên quan tới cái này nên ưu tiên VBA hơn ạ. Mong bác chỉ giáo!
Gửi lại , bạn còn trường hợp nào phải dùng VBA đưa ra thử tôi làm trên PQ được không?
Bài đã được tự động gộp:

 

File đính kèm

  • Tim du lieu.xlsx
    2.2 MB · Đọc: 11
Upvote 0
Gửi lại , bạn còn trường hợp nào phải dùng VBA đưa ra thử tôi làm trên PQ được không?
Bài đã được tự động gộp:
Em có thắc mắc là hiện tại hình như theo PQ này đang so sánh quantity từng dòng, nếu quantity ở các sheet kia lớn hơn sẽ lấy phải không ạ?
Nhưng em đang muốn cộng tổng quantity của các Sub-Category trước rồi mới so sánh quantity ở các sheet khác bác ạ.

Capture.JPG
 
Upvote 0
Upvote 0
Một cách dùng Power query, bấm refresh dữ liệu khi thêm dữ liệu ở cột A,B
Không biết Ton truoc, Ton sau bạn tính sao, nếu theo cách này thì làm tiếp
Từ ngày a show cái step merge column thì e thấy là giải pháp hoàn hảo thay cho vlookup, kể cả dictionary
 
Upvote 0
Ở diễn đàn này, VBA là Thần Tài và Dictionary là Ông Địa.
Thần PowerQuery cũng như Văn Thù, Phổ Hiền, xa lạ đối với họ.
Em không có ý xem trọng cái này, đánh giá thấp cái kia. Vẫn biết mỗi cái có lợi thế riêng, nhưng do kiến thức em hạn hẹp khó có thể lĩnh hội ngay cái mới được nên mong các bác giúp đỡ ạ.
 
Upvote 0
Ở diễn đàn này, VBA là Thần Tài và Dictionary là Ông Địa.
Thần PowerQuery cũng như Văn Thù, Phổ Hiền, xa lạ đối với họ.
Chắc cũng phải từ từ anh ạ. PQ mới xuất hiện từ bản 2016, có thể một số còn chưa nghe đến khái niệm này, còn dùng những bản office xưa cũ.
 
Upvote 0
Từ ngày a show cái step merge column thì e thấy là giải pháp hoàn hảo thay cho vlookup, kể cả dictionary
Cái Merge đó y như cái Join trong SQL, không phải giống Vlookup mà giống Lookup mới đúng cho phép dò tìm nhiều điều kiện, chưa kể còn mấy hình thức join khác rất ngon :)
 
Upvote 0
Upvote 0
Em có thắc mắc là hiện tại hình như theo PQ này đang so sánh quantity từng dòng, nếu quantity ở các sheet kia lớn hơn sẽ lấy phải không ạ?
Nhưng em đang muốn cộng tổng quantity của các Sub-Category trước rồi mới so sánh quantity ở các sheet khác bác ạ.

View attachment 248211
Đúng là đang code lấy vị trí đầu tiên lớn hơn, cộng tổng thì dễ nhưng chưa hình dung được dữ liệu trả về thế nào, vì tôi làm đúng yêu cầu bài #1 của bạn
 
Upvote 0
Đúng là đang code lấy vị trí đầu tiên lớn hơn, cộng tổng thì dễ nhưng chưa hình dung được dữ liệu trả về thế nào, vì tôi làm đúng yêu cầu bài #1 của bạn
Dữ liệu trả về sẽ điền cho tất cả các dòng cùng sub-category giống nhau, do quantity đã cộng tổng rồi nên chắc chắn lớn hơn từng dòng riêng lẻ bác ạ.
Cộng tổng là để đảm bảo dữ liệu trả về chắc chắn đủ đáp ứng cho đơn hàng có nhiều hơn 1 sub-category giống nhau.
Nếu được thì cột Ton sau = Ton truoc - quantity tổng ạ
 
Upvote 0
Table "Merge1" là join 2 điều kiện, nhiều điều kiện nữa làm tương tự
Bài đã được tự động gộp:

Dữ liệu trả về sẽ điền cho tất cả các dòng cùng sub-category giống nhau, do quantity đã cộng tổng rồi nên chắc chắn lớn hơn từng dòng riêng lẻ bác ạ.
Cộng tổng là để đảm bảo dữ liệu trả về chắc chắn đủ đáp ứng cho đơn hàng có nhiều hơn 1 sub-category giống nhau.
Nếu được thì cột Ton sau = Ton truoc - quantity tổng ạ
Mấy cái Order, ShipDate, Customer, Country thì trả sao bạn, nối chuỗi hả, bạn cho ví dụ mẫu đi!
Bài đã được tự động gộp:
 

File đính kèm

  • ex.xlsx
    101.9 KB · Đọc: 5
Lần chỉnh sửa cuối:
Upvote 0
Power Query dễ học hơn VBA rất nhiều.
Dữ kiệu cỡ 100 ngàn dòng thì không thể VIỆN CỚ gì để không dùng Power Query

Công ty làm việc với dữ liệu khủng mà từ chối không cập nhật phiên bản Excel là công ty tự đi vào ngõ cụt.
Lý do: công ty này phải dựa vào ngwoif xử lý hiện tại để đi làm (hoặc nhờ làm giùm) code VBA. Điều nay nâng tầm quan trọng của người xử lý. Tới mọt mức độ nào dó, người xử lý sẽ có thể áp lực với công ty. Điển hình là nghỉ ngang, và người tiếp quản sẽ lên GPE "cứu em với, chị làm trước em nghỉ ngang..."

Khi tôi tư vấn quản lý cho các cơ quan, gặp phòng nào có người sử dụng VBA hay các phần mềm download từ mạng hơi nhiều là tôi khyến cáo ban quản lý nên buộc người này phải ghi chép lại tài liệu và chu trình phát triển code của mình.
 
Lần chỉnh sửa cuối:
Upvote 0
Table "Merge1" là join 2 điều kiện, nhiều điều kiện nữa làm tương tự
Bài đã được tự động gộp:


Mấy cái Order, ShipDate, Customer, Country thì trả sao bạn, nối chuỗi hả, bạn cho ví dụ mẫu đi!
Bài đã được tự động gộp:
Ví dụ tổng cái Bookcases kia là 26794, sau khi chạy thì tìm được dòng đầu tiên mà qty lớn hơn 26794 thì điền các giá trị của dòng đó cho cả 3 dòng Bookcases đó ạ
Lúc đó: Ton sau = 27402 - 26794 = 608

Capture3.JPG
Capture4.JPG
Bài đã được tự động gộp:

Power Query dễ học hơn VBA rất nhiều.
Dữ kiệu cỡ 100 ngàn dòng thì không thể VIỆN CỚ gì để không dùng Power Query

Công ty làm việc với dữ liệu khủng mà từ chối không cập nhật phiên bản Excel là công ty tự đi vào ngõ cụt.
Lý do: công ty này phải dựa vào ngwoif xử lý hiện tại để đi làm (hoặc nhờ làm giùm) code VBA. Điều nay nâng tầm quan trọng của người xử lý. Tới mọt mức độ nào dó, người xử lý sẽ có thể áp lực với công ty. Điển hình là nghỉ ngang, và người tiếp quản sẽ lên GPE "cứu em với, chị làm trước em nghỉ ngang..."

Khi tôi tư vấn quản lý cho các cơ quan, gặp phòng nào có người sử dụng VBA hay các phần mềm download từ mạng hơi nhiều là tôi khyến cáo ban quản lý nên buộc người này phải ghi chép lại tài liệu và chu trình phát triển code của mình.
Với kiến thức của e bây giờ không áp lực được nổi đâu bác, chứ e mong thế lắm :)
Em trên diễn đàn cũng hay thấy bác chỉnh code giúp mn, bác giúp em xem code e paste bên trên xem cách tiếp cận đúng chưa với ạ
 
Lần chỉnh sửa cuối:
Upvote 0
Ví dụ tổng cái Bookcases kia là 26794, sau khi chạy thì tìm được dòng đầu tiên mà qty lớn hơn 26794 thì điền các giá trị của dòng đó cho cả 3 dòng Bookcases đó ạ
Lúc đó: Ton sau = 27402 - 26794 = 608

View attachment 248221
View attachment 248220
Bài đã được tự động gộp:


Với kiến thức của e bây giờ không áp lực được nổi đâu bác, chứ e mong thế lắm :)
Em trên diễn đàn cũng hay thấy bác chỉnh code giúp mn, bác giúp em xem code e paste bên trên xem cách tiếp cận đúng chưa với ạ
Bạn xét từ 2016 trước, làm ngồi mò, làm cho bạn lần nữa, bạn nhận file
 

File đính kèm

  • Tim du lieu.xlsx
    2.2 MB · Đọc: 17
Upvote 0
Bạn xét từ 2016 trước, làm ngồi mò, làm cho bạn lần nữa, bạn nhận file
Sao hay vậy bác =)) chuẩn ý e rồi ạ.
Bác cho e xin tài liệu hoặc link học cái này được k ạ.
Nếu được bác mô tả giúp em cách làm file này như nào với ạ.
Cảm ơn bác nhiều!
 
Upvote 0
Sao hay vậy bác =)) chuẩn ý e rồi ạ.
Bác cho e xin tài liệu hoặc link học cái này được k ạ.
Nếu được bác mô tả giúp em cách làm file này như nào với ạ.
Cảm ơn bác nhiều!
Tôi viết bằng code M trong Power query , tài liệu cơ bản thì kéo lên đầu trang có của thầy Ptm, bạn để data thật của bạn xem chạy nhanh hơn không, chép lại data 4 sheet 2013,2014,2015,2016 rồi bấm refresh bên sheet tìm kiếm
1603899983289.png
 
Upvote 0
Ví dụ tổng cái Bookcases kia là 26794, sau khi chạy thì tìm được dòng đầu tiên mà qty lớn hơn 26794 thì điền các giá trị của dòng đó cho cả 3 dòng Bookcases đó ạ
Lúc đó: Ton sau = 27402 - 26794 = 608

View attachment 248221
View attachment 248220
Bài đã được tự động gộp:


Với kiến thức của e bây giờ không áp lực được nổi đâu bác, chứ e mong thế lắm :)
Em trên diễn đàn cũng hay thấy bác chỉnh code giúp mn, bác giúp em xem code e paste bên trên xem cách tiếp cận đúng chưa với ạ
Thử code đồ cổ xem sao
Mã:
Sub XYZ()
  Application.ScreenUpdating = False
  Dim sArr(), aData(), Res(), iKey$, S, dic As Object
  Dim eRow&, sRow&, i&, j&, sh As Worksheet
    
  Set dic = CreateObject("scripting.dictionary")
  With Sheets("Tim kiem")
    eRow = .Range("A" & Rows.Count).End(xlUp).Row
    If eRow < 2 Then MsgBox ("Khong co du lieu"): Exit Sub
    aData = .Range("A2:B" & eRow).Value
  End With
  sRow = UBound(aData)
  For i = 1 To sRow
    iKey = aData(i, 1)
    dic.Item(iKey) = dic.Item(iKey) + aData(i, 2)
  Next i
  For Each sh In ThisWorkbook.Worksheets
    If sh.Name <> "Tim kiem" And sh.Name <> "Tru ton" Then
      sArr = sh.Range("A2:F" & sh.Range("A" & Rows.Count).End(xlUp).Row).Value
      sRow = UBound(sArr)
      For i = 1 To sRow
        iKey = sArr(i, 1)
        If dic.exists(iKey) Then
          If dic.exists(iKey & "#") = False Then
            If dic.Item(iKey) <= sArr(i, 6) Then
              dic(iKey & "#") = Array(sArr(i, 2), sArr(i, 3), sArr(i, 4), sArr(i, 5), sArr(i, 6))
              dic(iKey) = sArr(i, 6)
            End If
          End If
        End If
      Next i
    End If
  Next
  sRow = UBound(aData)
  ReDim Res(1 To sRow, 0 To 5)
  For i = 1 To sRow
    iKey = aData(i, 1)
    Res(i, 4) = dic.Item(iKey)
    If dic.exists(iKey & "#") Then
      S = dic.Item(iKey & "#")
      For j = 0 To 3
        Res(i, j) = S(j)
      Next j
    End If
    Res(i, 5) = Res(i, 4) - aData(i, 2)
  Next i
  With Sheets("Tim kiem")
    .Range("C2").Resize(sRow, 6).Value = Res
  End With
  Application.ScreenUpdating = True
End Sub
 
Upvote 0
Web KT

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

Back
Top Bottom