Giúp giảm số vòng lặp trong code đã viết (1 người xem)

Liên hệ QC

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

maytinhvp01

Thành viên thường trực
Tham gia
27/7/13
Bài viết
390
Được thích
179
Mình có vấn đề về tổng hợp số liệu. Cơ bản mình đã làm nhưng thấy với cách làm của mình số vòng lặp lớn quá. Gửi file lên nhờ anh em giúp sem có phương pháp nào nhanh hơn không. Yêu cầu trong file đã nghi.
Thank nhiều!
 

File đính kèm

Mình có vấn đề về tổng hợp số liệu. Cơ bản mình đã làm nhưng thấy với cách làm của mình số vòng lặp lớn quá. Gửi file lên nhờ anh em giúp sem có phương pháp nào nhanh hơn không. Yêu cầu trong file đã nghi.
Thank nhiều!
Tạm rút gọn code thế này.
PHP:
Sub tonghop()
Dim i As Long, j As Long, k As Long, sh, th
Set th = Worksheets("tonghop")
th.Range("F6:AO300").ClearContents
For Each sh In Worksheets
   If sh.Name <> "tonghop" Then
        For j = 6 To sh.[A6500].End(xlUp).Row
           For i = 6 To th.[A6500].End(xlUp).Row
               If th.Cells(i, 3) = sh.Cells(j, 3) Then
                   th.Range("F" & i & ":AO" & i).Value = sh.Range("F" & j & ":AO" & j).Value
                   Exit For
               End If
           Next
       Next
   End If
Next
End Sub
 
Upvote 0
Chạy thử code của bạn rùi Khá là nhanh. Nhưng những sản phẩm bên sheet tổng hợp mà có ca sản xuất là AB thì chưa cộng hết ở 2 sheet A và sheet B cái dòng bôi màu đỏ trong file
Mình cũng nghĩ cách khác nhung vẫn chết cái là cộng ỏ 2 ca A và B nên chạy vẫn ì ẹch quá khi ghép vào trương trình chung
Mã:
Sub tonghop()
Dim i As Long, k As Long, ran As Range
Worksheets("tonghop").Range("F5:AO300").ClearContents
With Worksheets("tonghop").Range("A5:AO" & Worksheets("tonghop").[C6500].End(xlUp).Row - 1)
'lay tu HC
    .AutoFilter 5, "HC"
    i = 6
    For Each ran In .Offset(1, 0).Resize(, 1).SpecialCells(12)
        Worksheets("tonghop").Range("F" & ran.Row & ":AO" & ran.Row).Value = Worksheets("HC").Range("F" & i & ":AO" & i).Value
        i = i + 1
    Next
    .AutoFilter
'lay tu A
    .AutoFilter 5, "A" & "*"
    i = 6
    For Each ran In .Offset(1, 0).Resize(, 1).SpecialCells(12)
        Worksheets("tonghop").Range("F" & ran.Row & ":AO" & ran.Row).Value = Worksheets("A").Range("F" & i & ":AO" & i).Value
         i = i + 1
    Next
    .AutoFilter
[COLOR=#ff0000]'lay tu B
    .AutoFilter 5, "B", xlOr, "AB"
    i = 6
    For Each ran In .Offset(1, 0).Resize(, 1).SpecialCells(12)
        If ran(, 6) = "B" Then
            Worksheets("tonghop").Range("F" & ran.Row & ":AO" & ran.Row).Value = Worksheets("B").Range("F" & i & ":AO" & i).Value
        Else
            For k = 6 To 41
                Worksheets("tonghop").Cells(ran.Row, k) = Worksheets("tonghop").Cells(ran.Row, k) + Worksheets("B").Cells(i, k)
            Next
        End If
        i = i + 1[/COLOR]
    Next
    .AutoFilter
End With
End Sub
phần màu đỏ mình làm nặng quá
 
Lần chỉnh sửa cuối:
Upvote 0
Chạy thử code của bạn rùi Khá là nhanh. Nhưng những sản phẩm bên sheet tong hop mà có ca sản xuất là AB thì chưa cộng hết ở 2 sheet A và sheet cái dòng bôi màu đỏ trong file

[/CODE]

Mình chỉ rút gọn code cho bạn biết cách giảm vòng lặp thôi. Mình không xem kết quả khi chạy code của bạn
 
Upvote 0
Mình không mở được file nhưng với dạng này thì mình thấy khó có thằng nào ăn được Dictionary kết hợp với mảng.
 
Upvote 0
Chạy thử code của bạn rùi Khá là nhanh. Nhưng những sản phẩm bên sheet tổng hợp mà có ca sản xuất là AB thì chưa cộng hết ở 2 sheet A và sheet B cái dòng bôi màu đỏ trong file
Mình cũng nghĩ cách khác nhung vẫn chết cái là cộng ỏ 2 ca A và B nên chạy vẫn ì ẹch quá khi ghép vào trương trình chung
Mã:
Sub tonghop()
Dim i As Long, k As Long, ran As Range
Worksheets("tonghop").Range("F5:AO300").ClearContents
With Worksheets("tonghop").Range("A5:AO" & Worksheets("tonghop").[C6500].End(xlUp).Row - 1)
'lay tu HC
    .AutoFilter 5, "HC"
    i = 6
    For Each ran In .Offset(1, 0).Resize(, 1).SpecialCells(12)
        Worksheets("tonghop").Range("F" & ran.Row & ":AO" & ran.Row).Value = Worksheets("HC").Range("F" & i & ":AO" & i).Value
        i = i + 1
    Next
    .AutoFilter
'lay tu A
    .AutoFilter 5, "A" & "*"
    i = 6
    For Each ran In .Offset(1, 0).Resize(, 1).SpecialCells(12)
        Worksheets("tonghop").Range("F" & ran.Row & ":AO" & ran.Row).Value = Worksheets("A").Range("F" & i & ":AO" & i).Value
         i = i + 1
    Next
    .AutoFilter
[COLOR=#ff0000]'lay tu B
    .AutoFilter 5, "B", xlOr, "AB"
    i = 6
    For Each ran In .Offset(1, 0).Resize(, 1).SpecialCells(12)
        If ran(, 6) = "B" Then
            Worksheets("tonghop").Range("F" & ran.Row & ":AO" & ran.Row).Value = Worksheets("B").Range("F" & i & ":AO" & i).Value
        Else
            For k = 6 To 41
                Worksheets("tonghop").Cells(ran.Row, k) = Worksheets("tonghop").Cells(ran.Row, k) + Worksheets("B").Cells(i, k)
            Next
        End If
        i = i + 1[/COLOR]
    Next
    .AutoFilter
End With
End Sub
phần màu đỏ mình làm nặng quá
Thử code này xem sao nha
Khi nào hứng mình viết cho code sử dụng dictionary chạy trong nháy mắt là xong
PHP:
Sub tonghop()
Dim sh As Worksheet, i As Long, j As Long, n As Long
Dim nguon(), kq()
   With Sheets("tonghop")
      .[F6:AO300].ClearContents
      kq = .Range(.[B6], .[B65536].End(3)).Resize(, 40).Value
         For Each sh In Worksheets
            If sh.Name <> "tonghop" Then
               nguon = sh.Range(sh.[B6], sh.[B65536].End(3)).Resize(, 40).Value
               For i = 1 To UBound(kq)
                  For j = 1 To UBound(nguon)
                     If nguon(j, 2) & nguon(j, 4) = kq(i, 2) & kq(i, 4) Then
                        For n = 5 To 40
                           kq(i, n) = kq(i, n) + nguon(j, n)
                        Next
                     End If
                  Next
               Next
            End If
         Next
      .[B6].Resize(i - 1, 40) = kq
   End With
End Sub
 
Upvote 0
Thử code này xem sao nha
Khi nào hứng mình viết cho code sử dụng dictionary chạy trong nháy mắt là xong
PHP:
Sub tonghop()
Dim sh As Worksheet, i As Long, j As Long, n As Long
Dim nguon(), kq()
   With Sheets("tonghop")
      .[F6:AO300].ClearContents
      kq = .Range(.[B6], .[B65536].End(3)).Resize(, 40).Value
         For Each sh In Worksheets
            If sh.Name <> "tonghop" Then
               nguon = sh.Range(sh.[B6], sh.[B65536].End(3)).Resize(, 40).Value
               For i = 1 To UBound(kq)
                  For j = 1 To UBound(nguon)
                     If nguon(j, 2) & nguon(j, 4) = kq(i, 2) & kq(i, 4) Then
                        For n = 5 To 40
                           kq(i, n) = kq(i, n) + nguon(j, n)
                        Next
                     End If
                  Next
               Next
            End If
         Next
      .[B6].Resize(i - 1, 40) = kq
   End With
End Sub

Nhớ đấy nhé mình sẽ nhớ để dòi code viết bàng dictionary
 
Upvote 0
Nhớ đấy nhé mình sẽ nhớ để dòi code viết bàng dictionary
Nhờ giúp code mà nghe giống ra lệnh quá. Loạn thật.
PHP:
Sub tonghop2()
Dim dic As Object
Dim sh As Worksheet, i As Long, j As Long, n As Long, k As Long, dk, dk2
Dim nguon(), dulieu(), kq()
Set dic = CreateObject("scripting.dictionary")
   With Sheets("Tonghop")
      nguon = .Range(.[B6], .[B65536].End(3)).Resize(, 40).Value
      ReDim kq(1 To UBound(nguon), 1 To 40)
   End With
   For i = 1 To UBound(nguon)
      dk = nguon(i, 2) & nguon(i, 4)
      If Not dic.exists(dk) Then
         k = k + 1
         dic.Add dk, k
         For n = 1 To 4
            kq(k, n) = nguon(i, n)
         Next
      End If
   Next
   For Each sh In Worksheets
      If sh.Name <> "Tonghop" Then
         dulieu = sh.Range(sh.[B6], sh.[B65536].End(3)).Resize(, 40).Value
         For j = 1 To UBound(dulieu)
            dk2 = dulieu(j, 2) & dulieu(j, 4)
            If dic.exists(dk2) Then
               For n = 5 To 40
                  kq(dic.Item(dk2), n) = kq(dic.Item(dk2), n) + dulieu(j, n)
               Next
            End If
         Next
      End If
   Next
Sheets("Tonghop").[B6].Resize(k, 40) = kq
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Nhờ giúp code mà nghe giống ra lệnh quá. Loạn thật.
PHP:
Sub tonghop2()
Dim dic As Object
Dim sh As Worksheet, i As Long, j As Long, n As Long, k As Long, dk, dk2
Dim nguon(), dulieu(), kq()
Set dic = CreateObject("scripting.dictionary")
   With Sheets("Tonghop")
      nguon = .Range(.[B6], .[B65536].End(3)).Resize(, 40).Value
      ReDim kq(1 To UBound(nguon), 1 To 40)
   End With
   For i = 1 To UBound(nguon)
      dk = nguon(i, 2) & nguon(i, 4)
      If Not dic.exists(dk) Then
         k = k + 1
         dic.Add dk, k
         For n = 1 To 4
            kq(k, n) = nguon(i, n)
         Next
      End If
   Next
   For Each sh In Worksheets
      If sh.Name <> "Tonghop" Then
         dulieu = sh.Range(sh.[B6], sh.[B65536].End(3)).Resize(, 40).Value
         For j = 1 To UBound(dulieu)
            dk2 = dulieu(j, 2) & dulieu(j, 4)
            If dic.exists(dk2) Then
               For n = 5 To 40
                  kq(dic.Item(dk2), n) = kq(dic.Item(dk2), n) + dulieu(j, n)
               Next
            End If
         Next
      End If
   Next
Sheets("Tonghop").[B6].Resize(k, 40) = kq
End Sub

Hi! lỡ câu nói thui mà. Thank ban nhièu nhé
 
Upvote 0
Mình tham gia 1 code tổng hợp dùng Dic và Mảng (Bạn Test tốc độ xem sao):

Mã:
Option Explicit
Sub TongHopDT()
Dim Dic  As Object, Sh As Worksheet
Dim Kq(), Tm, i, j, k
    Set Dic = CreateObject("Scripting.Dictionary")
       ReDim Kq(1 To Sheet1.[A65536].End(3).Row - 5, 1 To 42)
           For Each Sh In Worksheets
                Tm = Sh.Range("A6:AP" & Sh.[A65536].End(3).Row)
                     For i = 1 To UBound(Tm, 1)
                         If Sh.CodeName = "Sheet1" Then
                             Kq(i, 1) = i
                                  For j = 2 To 5
                                        Kq(i, j) = Tm(i, j)
                                             Next
                                          If Tm(i, 5) <> "" Then Dic.Add Tm(i, 3) & "@" & Tm(i, 5), i
                                       Else
                                   If Tm(i, 5) <> "" Then
                                For j = 6 To 42
                            If Tm(i, j) <> 0 Then Kq(Dic.Item(Tm(i, 3) & "@" & Tm(i, 5)), j) _
                            = Kq(Dic.Item(Tm(i, 3) & "@" & Tm(i, 5)), j) + Tm(i, j)
                       Next
                     End If
                 End If
             Next
         Next
Sheet1.Range("A6:AP6").Resize(UBound(Kq, 1)) = Kq
End Sub
 
Upvote 0
Tiêu đề là "giảm số vòng lặp" nhưng có vẻ bạn chủ ý muốn tăng hiệu suất.
Nếu thực sự muốn giảm số vòng lặp thì đem bài qua bên CSDL nhờ cụ Hai Lúa Miền Tây thử coi. Access SQL nó có sẵn hàm tổng hợp nên có khả năng viết gọn hơn. Tuy nhiên dùng ADO thì mất thêm thời gian kết nối, việc tăng hiệu suất hoàn toàn không thể bảo đảm.
 
Upvote 0
Tiêu đề là "giảm số vòng lặp" nhưng có vẻ bạn chủ ý muốn tăng hiệu suất.
Nếu thực sự muốn giảm số vòng lặp thì đem bài qua bên CSDL nhờ cụ Hai Lúa Miền Tây thử coi. Access SQL nó có sẵn hàm tổng hợp nên có khả năng viết gọn hơn. Tuy nhiên dùng ADO thì mất thêm thời gian kết nối, việc tăng hiệu suất hoàn toàn không thể bảo đảm.
Đúng rồi, đúng là mình muốn tăng tốc. Mình thì mới tìm hiểu về VBA với kiến thức hiện tại chưa thể rút gắn code và tăng tốc được, code viết ra còn thô sơ và nặng quá chỉ là giải quyết được công việc thôi nên một số đoạn code chạy lâu quá, có đoạn mất 40s àh.Nhưng mình sẽ học hỏi code hay trên diễn đàn và cải thiện dần dần vây!
Nói về thầy HAILUA thì đúng là về ADO thầy viết trên diễn đàn nhiều nhưng chưa có tài liệu cơ bản chẳng biết hỏi từ đâu. Mình dùng code nhưng phải hiểu được code mới dùng dù là không phải mình viết ra khi cần sửa đổi mới dễ không chảng biết sai ở đâu!!!
 
Lần chỉnh sửa cuối:
Upvote 0
Tiêu đề là "giảm số vòng lặp" nhưng có vẻ bạn chủ ý muốn tăng hiệu suất.
Nếu thực sự muốn giảm số vòng lặp thì đem bài qua bên CSDL nhờ cụ Hai Lúa Miền Tây thử coi. Access SQL nó có sẵn hàm tổng hợp nên có khả năng viết gọn hơn. Tuy nhiên dùng ADO thì mất thêm thời gian kết nối, việc tăng hiệu suất hoàn toàn không thể bảo đảm.

Bác ơi, trên Excel nếu dùng ADO hay DAO làm việc kiểu tổng hợp nhiều bảng như thế này về tốc độ mà nói khó ăn nổi mảng và Dic vì đã có lần em cũng Test rồi.
 
Upvote 0
Bác ơi, trên Excel nếu dùng ADO hay DAO làm việc kiểu tổng hợp nhiều bảng như thế này về tốc độ mà nói khó ăn nổi mảng và Dic vì đã có lần em cũng Test rồi.

Tôi có nói rõ là "Tuy nhiên dùng ADO thì mất thêm thời gian kết nối, việc tăng hiệu suất hoàn toàn không thể bảo đảm."
Tôi đâu có khuêyns khích dùng ADO bao giờ. Nó chỉ là một đề nghị để "giảm số vòng lặp"
 
Upvote 0
Mình tham gia 1 code tổng hợp dùng Dic và Mảng (Bạn Test tốc độ xem sao):

Mã:
Option Explicit
Sub TongHopDT()
Dim Dic  As Object, Sh As Worksheet
Dim Kq(), Tm, i, j, k
    Set Dic = CreateObject("Scripting.Dictionary")
       ReDim Kq(1 To Sheet1.[A65536].End(3).Row - 5, 1 To 42)
           For Each Sh In Worksheets
                Tm = Sh.Range("A6:AP" & Sh.[A65536].End(3).Row)
                     For i = 1 To UBound(Tm, 1)
                         If Sh.CodeName = "Sheet1" Then
                             Kq(i, 1) = i
                                  For j = 2 To 5
                                        Kq(i, j) = Tm(i, j)
                                             Next
                                          If Tm(i, 5) <> "" Then Dic.Add Tm(i, 3) & "@" & Tm(i, 5), i
                                       Else
                                   If Tm(i, 5) <> "" Then
                                For j = 6 To 42
                            If Tm(i, j) <> 0 Then Kq(Dic.Item(Tm(i, 3) & "@" & Tm(i, 5)), j) _
                            = Kq(Dic.Item(Tm(i, 3) & "@" & Tm(i, 5)), j) + Tm(i, j)
                       Next
                     End If
                 End If
             Next
         Next
Sheet1.Range("A6:AP6").Resize(UBound(Kq, 1)) = Kq
End Sub

Hôm nay ngồi test tốc đọ cho cùng một dạng số liệu có sẵn thì code của bạn fro nhất:
# 10 nhanh gấp #1 19 lần. ( xin lỗi các bạn nhé code trong file #1 có chút vấn đề mình đã sửa và test tốc độ)
#10 nhanh gấp #3 47 lần ( #2 code còn chưa hoàn chỉnh nên bỏ qua)
#10 nhanh gấp #6 2.5 lần
#10 nhanh gấp #8 1.5 lần
MÌNH ĐÁNH GIÁ BÀI CUẢ seland là tuyệt nhất!!!!
Vậy qua đây mình tự rút ra bài học qua bài #6 và dùng dic+mảng: Chuyển dữ liệu và kết quả ra mảng để xử lý thuật toán xong đâu vào đó mới đưa lại vào bảng tính thì tốc độ là tuyệt nhất. ( nói cho những bài có thể).
 
Lần chỉnh sửa cuối:
Upvote 0
Thuật toán nào cũng có khoảng tối ưu của nó. Theo thuật ngữ tiếng Anh, cái này gọi là sweet spot(s). Khi trường hợp (cấu hình, dữ liệu, vv...) của bạn lọt đúng vào khoảng sweet spot của thuật toán, nó sẽ chạy nhanh tối đa.

Nếu số keys mà bạn có (ở đây là số mã sản phẩm) lọt vào sweet spot của Dictionary Object thì bài toán sẽ là tuyệt diệu so với các phương pháp khác. Được cái khoảng sweet spot của Dictionary khá lớn cho nên rất dễ lọt vào.

Tuy nhiên, khi con số keys lên đến một mức nào đó thì các hàm của những phần mềm bom tấn sẽ chạy nhanh hơn vì chúng được chuyên gia thiết kế với những con toán tối ưu cho số lớn.
 
Upvote 0
Thuật toán nào cũng có khoảng tối ưu của nó. Theo thuật ngữ tiếng Anh, cái này gọi là sweet spot(s). Khi trường hợp (cấu hình, dữ liệu, vv...) của bạn lọt đúng vào khoảng sweet spot của thuật toán, nó sẽ chạy nhanh tối đa.

Nếu số keys mà bạn có (ở đây là số mã sản phẩm) lọt vào sweet spot của Dictionary Object thì bài toán sẽ là tuyệt diệu so với các phương pháp khác. Được cái khoảng sweet spot của Dictionary khá lớn cho nên rất dễ lọt vào.

Tuy nhiên, khi con số keys lên đến một mức nào đó thì các hàm của những phần mềm bom tấn sẽ chạy nhanh hơn vì chúng được chuyên gia thiết kế với những con toán tối ưu cho số lớn.

Đúng là tốc độ quá tuyệt vời. Sau khi áp dụng theo dic và mảng thì công viẹc đang từ 30s chạy nó giờ 7s.
!!!!
 
Upvote 0
Thuật toán nào cũng có khoảng tối ưu của nó. Theo thuật ngữ tiếng Anh, cái này gọi là sweet spot(s). Khi trường hợp (cấu hình, dữ liệu, vv...) của bạn lọt đúng vào khoảng sweet spot của thuật toán, nó sẽ chạy nhanh tối đa.

Nếu số keys mà bạn có (ở đây là số mã sản phẩm) lọt vào sweet spot của Dictionary Object thì bài toán sẽ là tuyệt diệu so với các phương pháp khác. Được cái khoảng sweet spot của Dictionary khá lớn cho nên rất dễ lọt vào.

Tuy nhiên, khi con số keys lên đến một mức nào đó thì các hàm của những phần mềm bom tấn sẽ chạy nhanh hơn vì chúng được chuyên gia thiết kế với những con toán tối ưu cho số lớn.
Mình viết code theo cách để mình dễ hiểu theo cách làm của dic và mảng nhưng không hiểu sao lại báo lỗi dòng bôi đỏ.Giúp thêm mình với
Mã:
Sub test()
Dim i As Long, j As Long, Kq, tim
Dim dic As Object
Set dic = CreateObject("scripting.dictionary")
With Worksheets("Tonghop")
    .Range("F6:AP" & .[B6500].End(xlUp).Row).ClearContents
    Kq = .Range("A6:AP" & .[B6500].End(xlUp).Row).Value
    For i = 1 To UBound(Kq, 1)
        If .Cells(i, 5) <> "" Then dic.Add .Cells(i, 3) & "@" & .Cells(i, 5), i
    Next
End With
With Worksheets("HC")
    tim = .Range("A6:AP" & .[B6500].End(xlUp).Row)
    For i = 1 To UBound(tim, 1)
        For j = 6 To 42
            If tim(i, j) <> 0 Then Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) = Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) + tim(i, j)
        Next
    Next
End With
With Worksheets("A")
    tim = .Range("A6:AP" & .[B6500].End(xlUp).Row)
    For i = 1 To UBound(tim, 1)
        For j = 6 To 42
            If tim(i, j) <> 0 Then Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) = Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) + tim(i, j)
        Next
    Next
End With
With Worksheets("B")
    tim = .Range("A6:AP" & .[B6500].End(xlUp).Row)
    For i = 1 To UBound(tim, 1)
        For j = 6 To 42
            If tim(i, j) <> 0 Then [COLOR=#ff0000]Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) = Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) + tim(i, j)[/COLOR]
        Next
    Next
End With
Worksheets("tonghop").Range("A6:AP6").Resize(UBound(Kq, 1)) = Kq
Worksheets("tonghop").Range("A6:AP6").Resize(UBound(Kq, 1)).Select
End Sub
 
Upvote 0
3 cái sheets HC. A, B bạn sử lý in hẹt nhau (hay ít nhất cũng gần in hệt nhau). Tại sao bạn không tách nó ra thành 1 hàm rồi làm cho gọn

private sub GiaiQuyet(ByVal sh As Worksheet, byVal dic As Object, byRef kq As Variant)
dim tim
tim = sh.Range("A6:AP" & .[B6500].End(xlUp).Row)
For i = 1 To UBound(tim, 1)
For j = 6 To 42
If tim(i, j) <> 0 Then Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) = Kq(dic.Item(tim(i, 3) & "@" & tim(i, 5)), j) + tim(i, j)
Next
Next
end sub

code chính:

call GiaiQuyet(Sheets("HC"), dic, kq)
call GiaiQuyet(Sheets("A"), dic, kq)
call GiaiQuyet(Sheets("B"), dic, kq)
 
Upvote 0

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

Back
Top Bottom