Các bác chỉ giúp, cần viết hàm tổng hợp số liệu. (1 người xem)

Liên hệ QC

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

bun_bo_hue

Thành viên chính thức
Tham gia
31/12/09
Bài viết
78
Được thích
11
Mình muốn dùng macro viết 1 hàm tổng hợp số liệu (như hình bên dưới). Nhưng yêu cầu hàm phải có tốc độ nhanh vì dữ liệu thực tế rất lớn (lưu dạng Excel2007 khoảng 40MB). Các pác siêu lập trình chỉ giúp mình với.

Cám ơn các bác.}}}}}

New Picture.jpg
 

File đính kèm

Lần chỉnh sửa cuối:
Bạn xem trong file đính kèm

Hàm tự tạo đó bạn!
--=0 --=0 --=0
 

File đính kèm

Upvote 0
Hàm tự tạo đó bạn!
--=0 --=0 --=0

Cám ơn bác nhiều lắm ạ. Hàm ra kết quả rất chính xác nhưng em vửa test thử hàm với 1000dòng, tốc độ hơi chậm 1 chút ^^ (nếu sử dụng cho data 300ngàn dòng thì chắc chậm nữa). Em kô có ý chê nhưng có cách nào làm cho nó nhanh lên kô pác ??? Hay đây là điểm yếu của các hàm tự tạo ?
 
Lần chỉnh sửa cuối:
Upvote 0
Tại bạn cần hàm mà!

Hãy xem macro có cải thiện được chút nào không nha!

(Chọn chương trình tại [E4] đó.)
 

File đính kèm

Upvote 0
Cám ơn bác nhiều lắm ạ. Hàm ra kết quả rất chính xác nhưng em vửa test thử hàm với 1000dòng, tốc độ hơi chậm 1 chút ^^ (nếu sử dụng cho data 300ngàn dòng thì chắc chậm nữa). Em kô có ý chê nhưng có cách nào làm cho nó nhanh lên kô pác ??? Hay đây là điểm yếu của các hàm tự tạo ?
Bạn thử đưa 1 file gần giống với thực tế nhất lên đây (file có 300,000 dòng ấy)
File lớn quá thì đưa lên mediafire nhé
----------------
Bài này chỉ có 1 "cửa" duy nhất có thể tăng tốc đó là: Dùng Array và Dictionary Object
 
Upvote 0
Bạn thử đưa 1 file gần giống với thực tế nhất lên đây (file có 300,000 dòng ấy)
File lớn quá thì đưa lên mediafire nhé
----------------
Bài này chỉ có 1 "cửa" duy nhất có thể tăng tốc đó là: Dùng Array và Dictionary Object

Em load file gốc lên rồi. 2 bác tham khảo giúp em ạ. Quan trọng là ra KẾT QUẢ và NHANH. Cách j cũng đc ạ.

@ Bác ChanhTQ: Cám ơn bác rất nhiều ạ, tốc độ file rất nhanh. Nhưng có 1 vấn đề là nếu chương trình đó lập lại n lần (ví dụ có nhiều dòng "Chương trình A - Monday" xuất hiện không chỉ 1 lần) thì nó sẽ ra kết quả tổng hợp là "Chương Trình A (Mon,Mon,Mon,Mon,Tue,Wed)", Monday cũng lập lại nhiều lần. Có cách nào tổng hợp thành "Chương Trình A (Mon,Tue,Wed)" đc kô bác ?. File gốc bác down link bên dưới về giúp em ạ.

@ Bác NDU : em load file 200ngàn dòng. Bác tham khảo cách làm giúp.

Cám ơn 2 bác rất nhiều.

https://www.yousendit.com/download/RlRwM25FMVhFd2RFQlE9PQ
 
Upvote 0
Đúng như Ndu noi, mình thử code sau với số lượng ít không cảm nhận được tốc độ

Mã:
Sub THop()
Dim Dic As Object, Cls As Range, tam1, tam2, i
Set Dic = CreateObject("Scripting.Dictionary")
With Sheet1
i = 1
For Each Cls In .Range(.[D4], .[D65536].End(3))
If Not Dic.Exists(Cls.Value) Then
Dic.Add Cls.Value, Chuoi(Cls)
End If
Next
tam1 = Dic.keys
tam2 = Dic.items
For i = 0 To Dic.Count - 1
.Cells(i + 5, "H") = tam1(i) & " ( " & tam2(i) & " )"
Next
End With
Set Dic = Nothing : Set Cls = Nothing
End Sub
'===============================================
Function Chuoi(ByVal Ch As String) As String
Dim Rng As Range, Dc As String, tam As String
With Sheet1.Range("D4:D65536")
Set Rng = .Find(Ch, LookIn:=xlValues)
If Not Rng Is Nothing Then
Dc = Rng.Address
 Do
If InStr(1, tam, Rng.Offset(, -1).Value) = 0 Then _
tam = IIf(Len(tam) > 0, tam & "-" & _
Rng.Offset(, -1).Value, Rng.Offset(, -1).Value)
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> Dc
End If
End With
Chuoi = tam
Set Rng = Nothing
End Function
P/s: File ban gửi nên nén lại, mình tải về không mở được vì mình dùng Ex 2003. Mình thử 2500 dòng rẹt 1 cái là xong
 
Lần chỉnh sửa cuối:
Upvote 0
Em load file gốc lên rồi. 2 bác tham khảo giúp em ạ. Quan trọng là ra KẾT QUẢ và NHANH. Cách j cũng đc ạ.

@ Bác ChanhTQ: Cám ơn bác rất nhiều ạ, tốc độ file rất nhanh. Nhưng có 1 vấn đề là nếu chương trình đó lập lại n lần (ví dụ có nhiều dòng "Chương trình A - Monday" xuất hiện không chỉ 1 lần) thì nó sẽ ra kết quả tổng hợp là "Chương Trình A (Mon,Mon,Mon,Mon,Tue,Wed)", Monday cũng lập lại nhiều lần. Có cách nào tổng hợp thành "Chương Trình A (Mon,Tue,Wed)" đc kô bác ?. File gốc bác down link bên dưới về giúp em ạ.

@ Bác NDU : em load file 200ngàn dòng. Bác tham khảo cách làm giúp.

Cám ơn 2 bác rất nhiều.

https://www.yousendit.com/download/RlRwM25FMVhFd2RFQlE9PQ
Chèn 1 Module và paste code này vào:
PHP:
Private Sub ConsolStr(ByVal sArr1, ByVal sArr2, ByVal Target As Range)
  Dim tArr1, tArr2, Arr(1 To 1000000, 1 To 2), Tmp, Tmp1, Tmp2, Dic1, Dic2
  Dim i As Long, j As Long, n As Long
  tArr1 = sArr1: tArr2 = sArr2
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  For i = LBound(tArr1, 1) To UBound(tArr1, 1)
    For j = LBound(tArr1, 2) To UBound(tArr1, 2)
      If tArr1(i, j) <> "" Then
        Tmp1 = tArr1(i, j): Tmp2 = tArr2(i, j)
        Tmp = Tmp1 & Tmp2
        If Not Dic1.Exists(Tmp) Then
          Dic1.Add Tmp, ""
          If Not Dic2.Exists(Tmp1) Then
            n = n + 1
            Dic2.Add Tmp1, n
            Arr(n, 1) = Tmp1
            Arr(n, 2) = Tmp2
          Else
            Arr(Dic2.Item(Tmp1), 2) = Arr(Dic2.Item(Tmp1), 2) & " - " & Tmp2
          End If
        End If
      End If
    Next j
  Next i
  Target.Resize(n, 2).Value = Arr
End Sub
PHP:
Sub Main()
  Dim sArr1, sArr2, Target As Range, TG As Double
  TG = Timer
  sArr1 = Sheet1.Range("F2:F1000000").Value
  sArr2 = Sheet1.Range("C2:C1000000").Value
  Set Target = Sheet1.Range("L3")
  Target.Resize(1000000, 2).Clear
  ConsolStr sArr1, sArr2, Target
  MsgBox Timer - TG
End Sub
Thiết lập sẳn cho bạn 1 triệu dòng đấy ---> Thời gian chạy xong code là 3 giây
Hài lòng chứ!
--------------
Lưu ý: Để chạy được code trên Excel 2007 thì phải lưu nó với định dạng xlsm nha
--------------
Up file lên cho bạn luôn đây:
http://up.4share.vn/f/7d4c4e4a4a4e4e44/ConsolStr.rar
 
Lần chỉnh sửa cuối:
Upvote 0
Chèn 1 Module và paste code này vào:
PHP:
Private Sub ConsolStr(ByVal sArr1, ByVal sArr2, ByVal Target As Range)
  Dim tArr1, tArr2, Arr(1 To 1000000, 1 To 2), Tmp, Tmp1, Tmp2, Dic1, Dic2
  Dim i As Long, j As Long, n As Long
  tArr1 = sArr1: tArr2 = sArr2
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  For i = LBound(tArr1, 1) To UBound(tArr1, 1)
    For j = LBound(tArr1, 2) To UBound(tArr1, 2)
      If tArr1(i, j) <> "" Then
        Tmp1 = tArr1(i, j): Tmp2 = tArr2(i, j)
        Tmp = Tmp1 & Tmp2
        If Not Dic1.Exists(Tmp) Then
          Dic1.Add Tmp, ""
          If Not Dic2.Exists(Tmp1) Then
            n = n + 1
            Dic2.Add Tmp1, n
            Arr(n, 1) = Tmp1
            Arr(n, 2) = Tmp2
          Else
            Arr(Dic2.Item(Tmp1), 2) = Arr(Dic2.Item(Tmp1), 2) & " - " & Tmp2
          End If
        End If
      End If
    Next j
  Next i
  Target.Resize(n, 2).Value = Arr
End Sub
PHP:
Sub Main()
  Dim sArr1, sArr2, Target As Range, TG As Double
  TG = Timer
  sArr1 = Sheet1.Range("F2:F1000000").Value
  sArr2 = Sheet1.Range("C2:C1000000").Value
  Set Target = Sheet1.Range("L3")
  Target.Resize(1000000, 2).Clear
  ConsolStr sArr1, sArr2, Target
  MsgBox Timer - TG
End Sub
Thiết lập sẳn cho bạn 1 triệu dòng đấy ---> Thời gian chạy xong code là 3 giây
Hài lòng chứ!
--------------
Lưu ý: Để chạy được code trên Excel 2007 thì phải lưu nó với định dạng xlsm nha

Bác NDU quá siêu }}}}}, quá VIP, độ CHÍNH XÁC TUYỆT ĐỐI còn TỐC ĐỘ thì tuyệt vời, cám ơn bác nhiều lắm ạ. }}}}}}}}}}}}}}}

1/ Nếu được, bác dành chút thời gian comment từng dòng code cho em hiểu được kô ạ ? Em cũng muốn học hỏi chút ít ^^? Nhìn vô như đám rừng, em đọc chả hiểu j cả. Cám ơn bác lần nữa ạ.

2/ Xin lỗi bác do em ghi chú trong file kô kĩ +-+-+-+. Khi thấy kết quả chạy ra (rất nhanh + chính xác) em thấy nó hơi dài ạ. Bác có thể chỉ giúp em :
- tương ứng từng dòng chương trình (ví dụ "chao buoi sang") sẽ là 1 dòng kết quả tổng hợp (chao buoi sang (Mon-Sun))
- Ngày chiếu chỉ lấy 3 kí tự đầu. Ví dụ : Monday thành Mon, Sunday thành Sun
- Ngày chiếu liệt kê sẽ rất dài. Có cách nào tổng hợp lại cho gọn. Ví dụ: Mon-Sun là chiếu từ T2 tới CN. Mon-Thu,Sun là chiếu từ T2 tới T5 và CN (thứ 6,7 kô chiếu)

Chi tiết xem file đính kèm giúp em ạ.@$@!^%

@ Có dịp offline nhất định gặp bác NDU để thỉnh giáo }}}}}
 

File đính kèm

Upvote 0
Bác NDU quá siêu }}}}}, quá VIP, độ CHÍNH XÁC TUYỆT ĐỐI còn TỐC ĐỘ thì tuyệt vời, cám ơn bác nhiều lắm ạ. }}}}}}}}}}}}}}}

1/ Nếu được, bác dành chút thời gian comment từng dòng code cho em hiểu được kô ạ ? Em cũng muốn học hỏi chút ít ^^? Nhìn vô như đám rừng, em đọc chả hiểu j cả. Cám ơn bác lần nữa ạ.

2/ Xin lỗi bác do em ghi chú trong file kô kĩ +-+-+-+. Khi thấy kết quả chạy ra (rất nhanh + chính xác) em thấy nó hơi dài ạ. Bác có thể chỉ giúp em :
- tương ứng từng dòng chương trình (ví dụ "chao buoi sang") sẽ là 1 dòng kết quả tổng hợp (chao buoi sang (Mon-Sun))
- Ngày chiếu chỉ lấy 3 kí tự đầu. Ví dụ : Monday thành Mon, Sunday thành Sun
- Ngày chiếu liệt kê sẽ rất dài. Có cách nào tổng hợp lại cho gọn. Ví dụ: Mon-Sun là chiếu từ T2 tới CN. Mon-Thu,Sun là chiếu từ T2 tới T5 và CN (thứ 6,7 kô chiếu)

Chi tiết xem file đính kèm giúp em ạ.@$@!^%

@ Có dịp offline nhất định gặp bác NDU để thỉnh giáo }}}}}
Riêng về việc lấy 3 ký tự của Weekday thì rất dễ
Chỉ cần sửa đoạn:
Tmp1 = tArr1(i, j): Tmp2 = tArr2(i, j)
thành:
Tmp1 = tArr1(i, j): Tmp2 = Left(tArr2(i, j), 3)
Các yêu cầu còn lại:
- Gom CHƯƠNG TRÌNH và NGÀY CHIẾU vào chung 1 cell (như chao buoi sang(Mon - Tue - Wed - Fri - Sat - Sun - Thu).... )
- Rút gọn chuổi trong NGÀY CHIẾU theo kiểu chao buoi sang(Mon ---> Sun).... hoặc chao buoi sang(Mon ---> Thu, Sun)...
Các yêu cầu này làm vẫn được nhưng đổi lại sẽ làm cho tốc độ code giảm đi rất nhiều (thậm chí là rất.. rất... nhiều).... Lý do vì sau khi code chạy xong ta lại phải chạy vòng lập lần nữa để xử lý chuổi (ít nhất là 2 vòng lập) ---> Vì thế mà tôi sẽ làm vầy:
- CHƯƠNG TRÌNH và NGÀY CHIẾU tôi để riêng 2 cột
- Có NGÀY CHIẾU nào, liệt kê ngày ấy (dù sao tách còn 3 ký tự thì chuổi cũng chẳng dài bao nhiêu, tối đa cũng chỉ có 7 từ)
----------------
Bạn nghĩ sao?
 
Upvote 0
Riêng về việc lấy 3 ký tự của Weekday thì rất dễ
Chỉ cần sửa đoạn:
Tmp1 = tArr1(i, j): Tmp2 = tArr2(i, j)
thành:
Tmp1 = tArr1(i, j): Tmp2 = Left(tArr2(i, j), 3)
Các yêu cầu còn lại:
- Gom CHƯƠNG TRÌNH và NGÀY CHIẾU vào chung 1 cell (như chao buoi sang(Mon - Tue - Wed - Fri - Sat - Sun - Thu).... )
- Rút gọn chuổi trong NGÀY CHIẾU theo kiểu chao buoi sang(Mon ---> Sun).... hoặc chao buoi sang(Mon ---> Thu, Sun)...
Các yêu cầu này làm vẫn được nhưng đổi lại sẽ làm cho tốc độ code giảm đi rất nhiều (thậm chí là rất.. rất... nhiều).... Lý do vì sau khi code chạy xong ta lại phải chạy vòng lập lần nữa để xử lý chuổi (ít nhất là 2 vòng lập) ---> Vì thế mà tôi sẽ làm vầy:
- CHƯƠNG TRÌNH và NGÀY CHIẾU tôi để riêng 2 cột
- Có NGÀY CHIẾU nào, liệt kê ngày ấy (dù sao tách còn 3 ký tự thì chuổi cũng chẳng dài bao nhiêu, tối đa cũng chỉ có 7 từ)
----------------
Bạn nghĩ sao?

Nếu có thời gian bác làm giúp em 2 cách luôn được không bác ? Cách1 theo đúng yêu cầu của em--=0, Cách2 theo yêu cầu của bác/-*+/.

À, bác có dạy thêm lập trình VBA không ạ ? Em đăng kí học riêng với bác được không ? Học vào ngày cuối tuần (thứ 7 hay CN đều được). Em hâm mộ bác quá }}}}}.

Nếu được nhắn tin cho em số điện thoại + tên của bác nhé. Số em đây : 0989.023530 - em tên HIỂN.@$@!^%
 
Upvote 0
Nếu có thời gian bác làm giúp em 2 cách luôn được không bác ? Cách1 theo đúng yêu cầu của em--=0, Cách2 theo yêu cầu của bác/-*+/.
Cũng khó chứ chẳng phải dễ ăn đâu ---> Chỉ nội xem trong chuổi Mon-Tue-Wed-Sun, làm sao biến nó thành Mon--->Web,Sun cũng rã rời rồi (vì phải sort chuổi, xem đoạn này "liên tục" thì lấy thằng đầu và cuối)
À, bác có dạy thêm lập trình VBA không ạ ? Em đăng kí học riêng với bác được không ? Học vào ngày cuối tuần (thứ 7 hay CN đều được). Em hâm mộ bác quá }}}}}.
Nếu được nhắn tin cho em số điện thoại + tên của bác nhé. Số em đây : 0989.023530 - em tên HIỂN.@$@!^%
Học tại đây là ngon lành rồi!
Cách đây 3 năm, khi tôi chưa biết gì, tôi đã học với sư phụ SA_DQ và sư phụ ptm0412 tại đây:
Chập chững đến VBA!
Giới thiệu Cơ bản về vòng lặp For . . . next
Bạn cũng nên vào đây nghiên cứu đi (ngoài ra có thể mua sách do GPE phát hành) ---> Sớm muộn bạn cũng thành cao thủ mà thôi
 
Upvote 0
Cũng khó chứ chẳng phải dễ ăn đâu ---> Chỉ nội xem trong chuổi Mon-Tue-Wed-Sun, làm sao biến nó thành Mon--->Web,Sun cũng rã rời rồi (vì phải sort chuổi, xem đoạn này "liên tục" thì lấy thằng đầu và cuối)

Học tại đây là ngon lành rồi!
Cách đây 3 năm, khi tôi chưa biết gì, tôi đã học với sư phụ SA_DQ và sư phụ ptm0412 tại đây:
Chập chững đến VBA!
Giới thiệu Cơ bản về vòng lặp For . . . next
Bạn cũng nên vào đây nghiên cứu đi (ngoài ra có thể mua sách do GPE phát hành) ---> Sớm muộn bạn cũng thành cao thủ mà thôi

Bác cũng bó tay thì em sao mà mơ làm được. Dù sao cũng cảm ơn bác nhiều.

Còn việc học, do em không có nhiều thời gian lên mạng nên muốn học trực tiếp bác cho nhanh (sách thì em có đủ rồi, mua ở ngòai và mua trên GPE nhưng toàn sách căn bản không à, em xem 1 ngày là xong). Bác biết gì thì dạy em cái đó thôi (vì em cũng hâm mộ bác), tất nhiên em học phải trả học phí rồi ^^. Được không bác ? Em đang muốn học từ những người như bác cho nhanh (tiết kiệm thời gian).
 
Lần chỉnh sửa cuối:
Upvote 0
Bác cũng bó tay thì em sao mà mơ làm được. Dù sao cũng cảm ơn bác nhiều.

Còn việc học, do em không có nhiều thời gian lên mạng nên muốn học trực tiếp bác cho nhanh (sách thì em có đủ rồi, mua ở ngòai và mua trên GPE nhưng toàn sách căn bản không à, em xem 1 ngày là xong). Bác biết gì thì dạy em cái đó thôi (vì em cũng hâm mộ bác), tất nhiên em học phải trả học phí rồi ^^. Được không bác ? Em đang muốn học từ những người như bác cho nhanh (tiết kiệm thời gian).
LÀM GÌ MÀ HỌC CHEN NGANG NHƯ VẬY ĐƯỢC
ĐƠN GIẢN NHƯ VIẾT THƯ CŨNG CẦN CÓ GỬI AI RỒI MỚI ĐẾN NỘI DUNG CHỨ.
BẠN ĐỊNH LÀM THEO PHIM CHƯỞNG CỦA HỒNG KÔNG À. TÉ XUỐNG NÚI LƯỢM ĐƯỢC BÍ KÍP , SAU ĐÓ TRỞ THÀNH CAO THỦ
HI HI
BẠN NÊN VÀO LINK NÀY RỒI SẼ CAO THỦ THÔI
http://www.giaiphapexcel.com/forum/showthread.php?6354-Giới-thiệu-Cơ-bản-về-vòng-lặp-For-.-.-.-next
 
Upvote 0
LÀM GÌ MÀ HỌC CHEN NGANG NHƯ VẬY ĐƯỢC
ĐƠN GIẢN NHƯ VIẾT THƯ CŨNG CẦN CÓ GỬI AI RỒI MỚI ĐẾN NỘI DUNG CHỨ.
BẠN ĐỊNH LÀM THEO PHIM CHƯỞNG CỦA HỒNG KÔNG À. TÉ XUỐNG NÚI LƯỢM ĐƯỢC BÍ KÍP , SAU ĐÓ TRỞ THÀNH CAO THỦ
HI HI
BẠN NÊN VÀO LINK NÀY RỒI SẼ CAO THỦ THÔI
http://www.giaiphapexcel.com/forum/showthread.php?6354-Giới-thiệu-Cơ-bản-về-vòng-lặp-For-.-.-.-next

Em cũng có căn bản rồi bác. Khôgn phải là không biết gì --=0. Chỉ là không siêu như mấy bác NDU mà thôi --> học trực tiếp là hay nhất.

Năn nỉ quá trời mà bác NDU vẫn không chịu thì em đành tự mò thôi vậy +-+-+-+
 
Upvote 0
Em cũng có căn bản rồi bác. Khôgn phải là không biết gì --=0. Chỉ là không siêu như mấy bác NDU mà thôi --> học trực tiếp là hay nhất.

Năn nỉ quá trời mà bác NDU vẫn không chịu thì em đành tự mò thôi vậy +-+-+-+
Tôi nghĩ lại thấy diễn đàn này cũng có rất nhiều bạn có nhu cầu học VBA như bạn! Vậy sao không tập trung lại chừng 20 người rồi mở lớp?
Lúc trước Bình Admin phát động mà chẳng thấy ai nói gì
Nếu lớp được tổ chức thì sẽ được toàn các cao thủ giảng dạy
 
Upvote 0
Chào các bạn,

Mình mới tham gia học về VBA, cũng xin tham gia đóng góp 1 phần.

Em làm hơi dài dòng tí

Bước 1: tỪ dữ liệu ==> new format
Bước 2: New format ==> Tổng hợp

Các anh chị test thử và cho em nhận xét nhe.

Cám ơn các anh chị nhiều


'====================================================
Sub Total()
Dim a(7)
Dim b(20)
Cells(2, 1).Select
t = Range(Selection, Selection.End(xlDown)).Count
For i = 1 To t
If Cells(i + 1, 1) <> "" Then
For j = 1 To 7
If Cells(i + 1, j + 1) <> "" Then
a(j) = Cells(1, j + 1)
Else
a(j) = ""
End If
Next
Close
b(i) = a(1) & " " & a(2) & " " & a(3) & " " & a(4) & " " & a(5) & " " & a(6) & " " & a(7)
Cells(i + 1, 9) = b(i)
For k = 1 To 5
Cells(i + 1, 9) = Trim(Replace(Cells(i + 1, 9), " ", " "))
Next
Close
Cells(i + 1, 9) = Cells(i + 1, 1) + " (" + Replace(Cells(i + 1, 9), " ", ", ") + ")"
Else
End If
Next
Close
End Sub
'===================================================================
Sub make_newformat()
Worksheets("Sheet1").Cells(2, 1).Select
t = Range(Selection, Selection.End(xlDown)).Count
For i = 1 To t
Cells(i + 1, 3) = Cells(i + 1, 2) & "." & Cells(i + 1, 1)
Cells(i + 1, 4) = "x"
Next
Close
Cells(2, 2).Select
t = Range(Selection, Selection.End(xlDown)).Count
For i = 1 To t
Worksheets("Sheet2").Cells(i + 1, 1) = Worksheets("Sheet1").Cells(i + 1, 2)
Next
Close
Sheets("Sheet2").Select
Cells(2, 1).Select
Range(Selection, Selection.End(xlDown)).Select
ActiveSheet.Range("$A$1:$A$20").RemoveDuplicates Columns:=1, Header:=xlNo
Cells(2, 1).Select
k = Range(Selection, Selection.End(xlDown)).Count
For i = 1 To k
For j = 1 To 7
Worksheets("Sheet2").Cells(i + 1, j + 1) = Application.WorksheetFunction.vlookup(Cells(i + 1, 1) & "." & Cells(1, j + 1), Worksheets("Sheet1").Range("C2:D20"), 2, 0)
On Error Resume Next
Next
Close
Next
Close
End Sub
'=======================================================
Sub main()
make_newformat
Total
End Sub
 

File đính kèm

Upvote 0
Chào các bạn,

Mình mới tham gia học về VBA, cũng xin tham gia đóng góp 1 phần.

Em làm hơi dài dòng tí

Bước 1: tỪ dữ liệu ==> new format
Bước 2: New format ==> Tổng hợp

Các anh chị test thử và cho em nhận xét nhe.

Cám ơn các anh chị nhiều
Đại ca ơi! Vấn đề ở đây không phải nằm ở chổ có viết code được hay không mà là: PHẢI VIẾT ĐỂ CODE CHẠY VỚI DỮ LIỆU LỚN VÀ TỐC ĐỘ NHANH
Dữ liệu gốc của người ta là 300000 dòng đấy đại ca à! Đại ca đã thử chưa?
 
Upvote 0
Anh cho em xin 300.000 dòng dữ liệu, em sẽ chạy thử xem.

Em chưa thử 300.000 dòng ạ.

Cho em xin file với

Cám ơn anh nhiều
 
Upvote 0
Upvote 0
Em cám ơn anh rất nhiều, đoạn mã của em chạy cho 300,000 dòng chậm quá hà. em mới biết viết thôi, chưa biết làm thế nào cho nó giảm lại. Em sẽ học hỏi anh và các anh chị nhiều hơn.

Cám ơn anh rất nhiều


File gốc đây
http://www.mediafire.com/?14z8z4v6879wibn
Trong ấy đang có code của tôi! Bạn cứ viết thế nào mà ra kết quả giống như tôi là ĂN TIỀN
Ẹc... Ẹc...
 
Upvote 0
Em cám ơn anh rất nhiều, đoạn mã của em chạy cho 300,000 dòng chậm quá hà. em mới biết viết thôi, chưa biết làm thế nào cho nó giảm lại. Em sẽ học hỏi anh và các anh chị nhiều hơn.

Cám ơn anh rất nhiều
Bài này quá lớn với những bạn mới học! Tuy nhiên, đọc file của bạn tôi thấy có cách bố trí dữ liệu xuất thế này:

untitled.JPG

Đây cũng là cách bố trí hay! Tác giả topic cũng nên lưu ý xem liệu ta có nên xuất dữ liệu theo kiểu này không (trực quan đấy chứ)
 
Upvote 0
Mình có 1 ý là sử dụng công thức thay cho việc rà soát cả vùng sẽ bớt đi rất nhiều thời gian. Mặt khác, mảng tên thứ trong tuần đã đwợc tạo theo trình tự nên kết quả luôn được sắp xếp (Khỏi phải lo đoạn này). Code như sau:

Mã:
Sub THop()
Dim Dic As Object, Cls As Range, tam1, tam2, i
Set Dic = CreateObject("Scripting.Dictionary")
With Sheet1
i = 1
For Each Cls In .Range(.[D4], .[D65536].End(3))
If Not Dic.Exists(Cls.Value) Then
Dic.Add Cls.Value, Taochuoi(Cls)
End If
Next
tam1 = Dic.keys
tam2 = Dic.items
For i = 0 To Dic.Count - 1
.Cells(i + 7, "F") = tam1(i) & " ( " & tam2(i) & " )"
Next
End With
Set Dic = Nothing: Set Cls = Nothing
End Sub
'===============================================
Function Taochuoi(ByVal Dk As String) As String
Dim Ar(), i, tam
Dim rg1, rg2, Ir, ch
Ar = Array("Mon", "Tue", "Wed", "Fri", "Thu", "Sat", "Sun")
With Sheet1
Ir = .[D65536].End(3).Row
rg1 = .Name & "!" & .[C4].Resize(Ir - 3).Address
rg2 = .Name & "!" & .[D4].Resize(Ir - 3).Address
For i = 0 To 6
ch = "=SUMPRODUCT(--(" & rg2 & "=""" & Dk & """" & "),--(" & rg1 & "=""" & Ar(i) & """" & "))"
If Evaluate(ch) > 0 Then tam = tam & IIf(Len(tam) > 0, "-", "") & Ar(i)
Next
End With
Taochuoi = tam
End Function
Mình nhờ Ndu test giúp xem thời gian ra sao nhé.
 

File đính kèm

Upvote 0
Mình có 1 ý là sử dụng công thức thay cho việc rà soát cả vùng sẽ bớt đi rất nhiều thời gian. Mặt khác, mảng tên thứ trong tuần đã đwợc tạo theo trình tự nên kết quả luôn được sắp xếp (Khỏi phải lo đoạn này). Code như sau:
Mình nhờ Ndu test giúp xem thời gian ra sao nhé.
Cách này chậm lắm anh à! Vì SUMPRODUCT với nhiều điều kiện thì cũng tương đương với vòng lập For thôi (em thử code của anh, nó treo máy luôn)
Em đang nghĩ đến 1 hướng khác: Dùng PivotTable được không ta? Ai thạo PivotTable trên Excel 2007 làm thử xem (em thấy khó thao tác quá)
 
Upvote 0
Cách này chậm lắm anh à! Vì SUMPRODUCT với nhiều điều kiện thì cũng tương đương với vòng lập For thôi (em thử code của anh, nó treo máy luôn)
Em đang nghĩ đến 1 hướng khác: Dùng PivotTable được không ta? Ai thạo PivotTable trên Excel 2007 làm thử xem (em thấy khó thao tác quá)

Pivot~2007 cũng dễ thao tác mà Bác,
Theo bố trí kiểu bài 22 của Bác thì nó sẽ là thế này:
 

File đính kèm

Upvote 0
Thử "dọc" nó thôi

Mày mò viết thử xuất ra bảng, tốc độ vẫn chậm, phải mất 7,5 giây
Thay Match bằng một vòng lặp ==> kết quả vẫn thế, chậm hơn tí tẹo
Mệt quá, "hổng" mò nữa
Mã:
Public Sub MoMam()
    Dim Vung As Range, d As Object, Cll As Range, K As Long, Mg(1 To 300000, 1 To 8), TG As Double, iNgay As Range
    Set d = CreateObject("scripting.dictionary")
    Set Vung = Range([f2], [f500000].End(xlUp))
    Set iNgay = [m2:s2]
    TG = Timer:    K = 1
        For Each Cll In Vung
            If Not d.exists(Cll.Value) Then
                d.Add Cll.Value, K
                Mg(K, 1) = Cll.Value
                Mg(K, Application.WorksheetFunction.Match(Cll.Offset(, -3), iNgay, 0) + 1) = "x"
                K = K + 1
            Else
                Mg(d.Item(Cll.Value), Application.WorksheetFunction.Match(Cll.Offset(, -3), iNgay, 0) + 1) = "x"
            End If
        Next
    [l3].Resize(K, 8) = Mg
    MsgBox Timer - TG
End Sub
 
Upvote 0
Mày mò viết thử xuất ra bảng, tốc độ vẫn chậm, phải mất 7,5 giây
Thay Match bằng một vòng lặp ==> kết quả vẫn thế, chậm hơn tí tẹo
Mệt quá, "hổng" mò nữa
Mã:
Public Sub MoMam()
    Dim Vung As Range, d As Object, Cll As Range, K As Long, Mg(1 To 300000, 1 To 8), TG As Double, iNgay As Range
    Set d = CreateObject("scripting.dictionary")
    Set Vung = Range([f2], [f500000].End(xlUp))
    Set iNgay = [m2:s2]
    TG = Timer:    K = 1
        For Each Cll In Vung
            If Not d.exists(Cll.Value) Then
                d.Add Cll.Value, K
                Mg(K, 1) = Cll.Value
                Mg(K, Application.WorksheetFunction.Match(Cll.Offset(, -3), iNgay, 0) + 1) = "x"
                K = K + 1
            Else
                Mg(d.Item(Cll.Value), Application.WorksheetFunction.Match(Cll.Offset(, -3), iNgay, 0) + 1) = "x"
            End If
        Next
    [l3].Resize(K, 8) = Mg
    MsgBox Timer - TG
End Sub
Nguyên tắc để tăng tốc là thế này nè anh ơi:
1> Với bài toán Unique thì không có thuật toán nào qua mặt được với Dictionary và Collect (dùng MACTH, COUNTIF hoặc Find đều chậm)
2> Không nên thực thi tính toán với RANGE mà phải chuyển mọi thứ thuộc RANGE thành ARRAY ---> Ví dụ thế này
PHP:
Dim Clls as Range
For Each Clls in Range("C1:C50000")
......
Next
thì ta nên sửa thành:
PHP:
Dim tmpArr, i as Long
tmpArr = Range("C1:C50000").Value
For i = LBound(tmpArr, 1) to UBound(tmpArr,1)
......
Next
Khi này, muốn tính toán gì thì sẽ tính trên Array ---> Cuối cùng xuất kết quả ra 1 lượt
--------------------------
Em viết code này như vầy:
PHP:
Private Sub ConsolStr2(ByVal sArr1, ByVal sArr2, ByVal Target As Range)
  Dim tArr1, tArr2, Arr(1 To 1000000, 1 To 8)
  Dim wd As New Collection, wdArr, Dic1, Dic2
  Dim i As Long, j As Long, n As Long, k As Long
  Dim Tmp As String, Tmp1 As String, Tmp2 As String
  tArr1 = sArr1: tArr2 = sArr2
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  wdArr = Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
  Set wd = New Collection
  For k = 0 To 6
    wd.Add CStr(k + 2), wdArr(k)
  Next k
  For i = LBound(tArr1, 1) To UBound(tArr1, 1)
    For j = LBound(tArr1, 2) To UBound(tArr1, 2)
      If tArr1(i, j) <> "" Then
        Tmp1 = tArr1(i, j): Tmp2 = tArr2(i, j)
        Tmp = Tmp1 & Tmp2
        If Not Dic1.Exists(Tmp) Then
          Dic1.Add Tmp, ""
          If Not Dic2.Exists(Tmp1) Then
            n = n + 1
            Dic2.Add Tmp1, n
            Arr(n, 1) = Tmp1
            Arr(n, wd.Item(Tmp2)) = "X"
          Else
            Arr(Dic2.Item(Tmp1), wd.Item(Tmp2)) = "X"
          End If
        End If
      End If
    Next j
  Next i
  Target.Resize(n, 8).Value = Arr
End Sub
PHP:
Sub Main2()
  Dim sArr1, sArr2, Target As Range, TG As Double
  TG = Timer
  sArr1 = Sheet1.Range("F2:F1000000").Value
  sArr2 = Sheet1.Range("C2:C1000000").Value
  Set Target = Sheet1.Range("L3")
  Target.Resize(1000000, 8).Clear
  ConsolStr2 sArr1, sArr2, Target
  MsgBox Timer - TG
End Sub
Tốc độ là 4 giây
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn Ndu nhiều

Hihi
Mò ra rồi
Tốc độ KHỦNG
Cám ơn ndu nhiều nhiều
Mã:
Public Sub LaiMo()
    Dim Vung, d As Object, Cll As Range, K As Long, Mg(1 To 300000, 1 To 8), TG As Double, iNgay, I, J, Ngay, Vung2
    Set d = CreateObject("scripting.dictionary")
     Vung = Range([f2], [f500000].End(xlUp)).Value
     Vung2 = Range([c2], [c500000].End(xlUp)).Value
    iNgay = Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    TG = Timer:    K = 1
        For I = LBound(Vung, 1) To UBound(Vung, 1)
        For J = 0 To 6
            If iNgay(J) = Vung2(I, 1) Then Ngay = J + 2: Exit For
        Next
            If Not d.exists(Vung(I, 1)) Then
                d.Add Vung(I, 1), K
                Mg(K, 1) = Vung(I, 1)
                Mg(K, Ngay) = "x"
                K = K + 1
            Else
                Mg(d.Item(Vung(I, 1)), Ngay) = "x"
            End If
        Next
    [l3].Resize(K, 8) = Mg
    MsgBox Timer - TG
End Sub
 
Upvote 0
Hihi
Mò ra rồi
Tốc độ KHỦNG
Cám ơn ndu nhiều nhiều
Mã:
Public Sub LaiMo()
    Dim Vung, d As Object, Cll As Range, K As Long, Mg(1 To 300000, 1 To 8), TG As Double, iNgay, I, J, Ngay, Vung2
    Set d = CreateObject("scripting.dictionary")
     Vung = Range([f2], [f500000].End(xlUp)).Value
     Vung2 = Range([c2], [c500000].End(xlUp)).Value
    iNgay = Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    TG = Timer:    K = 1
        For I = LBound(Vung, 1) To UBound(Vung, 1)
        For J = 0 To 6
            If iNgay(J) = Vung2(I, 1) Then Ngay = J + 2: Exit For
        Next
            If Not d.exists(Vung(I, 1)) Then
                d.Add Vung(I, 1), K
                Mg(K, 1) = Vung(I, 1)
                Mg(K, Ngay) = "x"
                K = K + 1
            Else
                Mg(d.Item(Vung(I, 1)), Ngay) = "x"
            End If
        Next
    [l3].Resize(K, 8) = Mg
    MsgBox Timer - TG
End Sub
Anh con cò "ăn cắp" thời gian nha ---> Lý ra dòng TG = Timer phải nằm ở trên cùng (dưới dòng khai báo biến)
Mà cái này nhanh hơn nữa nè:
PHP:
Sub ConsolStr3()
  Dim tArr1, tArr2, Arr(1 To 300000, 1 To 8), ScrCtr, Dic1, Dic2
  Dim i As Long, j As Long, n As Long, K As Long, TG As Double
  Dim Tmp As String, Tmp1 As String, Tmp2 As String
  TG = Timer
  tArr1 = Sheet1.Range("F2:F300000").Value
  tArr2 = Sheet1.Range("C2:C300000").Value
  Set ScrCtr = CreateObject("MSScriptControl.ScriptControl")
  ScrCtr.Language = "VBScript"
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  For i = 1 To UBound(tArr1)
    If tArr1(i, 1) <> "" Then
      Tmp1 = tArr1(i, 1): Tmp2 = tArr2(i, 1): Tmp = Tmp1 & Tmp2
      If Not Dic1.Exists(Tmp) Then
        Dic1.Add Tmp, ""
        If Not Dic2.Exists(Tmp1) Then
          n = n + 1
          Dic2.Add Tmp1, n
          Arr(n, 1) = Tmp1
          Arr(n, ScrCtr.Eval("vb" & Tmp2) + 1) = "X"
        Else
          Arr(Dic2.Item(Tmp1), ScrCtr.Eval("vb" & Tmp2) + 1) = "X"
        End If
      End If
    End If
  Next i
  Sheet1.Range("L3").Resize(n, 8).Value = Arr
  MsgBox Timer - TG
End Sub
-------------------
Nhân tiện đố mọi người biết code trên đã dùng thuật toán gì mà... chẳng thấy "Monday", "Tueday"... nó nằm ở đâu cả vậy?
Ẹc... Ẹc...
 
Upvote 0
Tôi nghĩ lại thấy diễn đàn này cũng có rất nhiều bạn có nhu cầu học VBA như bạn! Vậy sao không tập trung lại chừng 20 người rồi mở lớp?
Lúc trước Bình Admin phát động mà chẳng thấy ai nói gì
Nếu lớp được tổ chức thì sẽ được toàn các cao thủ giảng dạy

20người mới mở đc lớp hả bác ? Vậy khi nào mới có đủ 20người. Bác dạy em trước kô đc hả bác .
 
Upvote 0
Cũng khó chứ chẳng phải dễ ăn đâu ---> Chỉ nội xem trong chuổi Mon-Tue-Wed-Sun, làm sao biến nó thành Mon--->Web,Sun cũng rã rời rồi (vì phải sort chuổi, xem đoạn này "liên tục" thì lấy thằng đầu và cuối)

Học tại đây là ngon lành rồi!
Cách đây 3 năm, khi tôi chưa biết gì, tôi đã học với sư phụ SA_DQ và sư phụ ptm0412 tại đây:
Chập chững đến VBA!
Giới thiệu Cơ bản về vòng lặp For . . . next
Bạn cũng nên vào đây nghiên cứu đi (ngoài ra có thể mua sách do GPE phát hành) ---> Sớm muộn bạn cũng thành cao thủ mà thôi

Bác NDU ơi, em làm được rồi :D. Em ngâm cứu dựa trên nền tảng code của bác, em đã SORT và gộp lại được thứ rồi (ví dụ : "Mon,Fri,Sat,Sun" sẽ thành "2,6-8"). Tốc độ cũng nhanh chả kém nguyên bản code ban đầu của bác (dữ liệu 300ngàn dòng khi chạy code không thấy sự khác biệt khi em thêm code của em vào). Cám ơn bác nhiều lắm ạ ^^.
 
Upvote 0

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

Back
Top Bottom