Chuyên đề Bài tập VBA (3 người xem)

  • Thread starter Thread starter SA_DQ
  • Ngày gửi Ngày gửi
Liên hệ QC

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

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia
8/6/06
Bài viết
14,611
Được thích
22,931
Nghề nghiệp
U80
Bài I: Chuyển dữ liệu từ 1 bảng tổng hợp
Số liệu ban đầu như sau:
| A | B 1 |Project1|Item01, Item03, Item08, Item09
2 |Project2|Item10, Item30, Item80, Item90
(Bảng 1)

Giờ muốn có 1 macro để chuyển bảng dữ liệu này thành bảng sau:
|D | E 1 |Project1|Item01
2 |Project1|Item03
3 |Project1|Item08
4 |Project1|Item09
5| Project2|Item10
. . .|. . .
8 |Project2|Item90

(Bảng 2)
Bài II: Hãy giúp tôi chuyển dữ liệu từ bảng 2 thành bảng 1
(húc Mừng Xuân Mới!
 
Chỉnh sửa lần cuối bởi điều hành viên:
Tôi đang tìm hiểu về Dictionary, tìm hiểu mãi nhưng không thấy chỗ nào nói về CStr, CDbl,Item trong đoạn Code sau là gì? Rất mong nhận được sự trợ giúp của mọi người.
PHP:
Public Dic As Object
Sub DienDG()
  Dim pList, sArray, tmp1 As String, tmp2 As Double, i As Long, j As Long
  On Error Resume Next
  If Dic Is Nothing Then
    Set Dic = CreateObject("Scripting.Dictionary")
    pList = Sheet1.Range("A2:B1000").Value
    For i = 1 To UBound(pList, 1)
      If pList(i, 1) <> "" Then
        tmp1 = CStr(pList(i, 1))
        tmp2 = CDbl(pList(i, 2))
        If Not Dic.Exists(tmp1) Then Dic.Add tmp1, tmp2
      End If
    Next
  End If
  With Sheet2.Range("A2:E10000")
    sArray = .Value
    For i = 1 To UBound(sArray, 1)
      If sArray(i, 1) <> "" Then
        sArray(i, 4) = Dic.Item(CStr(sArray(i, 2)))
        sArray(i, 5) = sArray(i, 3) * sArray(i, 4)
      End If
    Next
    .Value = sArray
  End With
End Sub
 
Upvote 0
Tôi đang tìm hiểu về Dictionary, tìm hiểu mãi nhưng không thấy chỗ nào nói về CStr, CDbl,Item trong đoạn Code sau là gì? Rất mong nhận được sự trợ giúp của mọi người.
PHP:
Public Dic As Object
Sub DienDG()
  Dim pList, sArray, tmp1 As String, tmp2 As Double, i As Long, j As Long
  On Error Resume Next
  If Dic Is Nothing Then
    Set Dic = CreateObject("Scripting.Dictionary")
    pList = Sheet1.Range("A2:B1000").Value
    For i = 1 To UBound(pList, 1)
      If pList(i, 1) <> "" Then
        tmp1 = CStr(pList(i, 1))
        tmp2 = CDbl(pList(i, 2))
        If Not Dic.Exists(tmp1) Then Dic.Add tmp1, tmp2
      End If
    Next
  End If
  With Sheet2.Range("A2:E10000")
    sArray = .Value
    For i = 1 To UBound(sArray, 1)
      If sArray(i, 1) <> "" Then
        sArray(i, 4) = Dic.Item(CStr(sArray(i, 2)))
        sArray(i, 5) = sArray(i, 3) * sArray(i, 4)
      End If
    Next
    .Value = sArray
  End With
End Sub
Hàm CStr() là hàm chuyển đổi sang kiểu String
Hàm CDbl() là hàm chuyển đổi biểu thức sang dạng số kiểu Double VD: CDbl(8*3) sẽ cho kết quả 24
 
Upvote 0
Tôi đang tìm hiểu về Dictionary, tìm hiểu mãi nhưng không thấy chỗ nào nói về CStr, CDbl,Item trong đoạn Code sau là gì? Rất mong nhận được sự trợ giúp của mọi người.
Item là phương thức của Dictionay nó dùng để truy xuất phần tử thứ item trong Keys của Dictionary, Cstr dùng để chuyển đổi số thành chuỗi mà dùng để so sánh trong VBA Code thôi ta không thể chuyển chúng thành chuỗi rồi gán xuống sheet dạng text được, tương tự CDbl chuyển chuỗi thành số vài lời cùng bạn
 
Upvote 0
Hàm CStr() là hàm chuyển đổi sang kiểu String
Hàm CDbl() là hàm chuyển đổi biểu thức sang dạng số kiểu Double VD: CDbl(8*3) sẽ cho kết quả 24
Mấy bạn ở trên đã nói về ý nghĩa của CStr và CDbl rồi.. tôi xin nói thêm tại sao phải dùng mấy "thằng" này
Là do không chắc dữ liệu trên sheet có chuẩn hay không... Nhiều khi thấy rõ ràng là số mà thật ra nó lại là Text... Vì thế nếu cho dữ liệu vào CStr thì ăn chắc nó sẽ chuyển thành Text và khi vào CDbl thì ăn chắc nó sẽ chuyển thành kiểu số (Double)
(kinh nghiệm xương máu khi làm việc với dữ liệu ngày tháng)
 
Upvote 0
Tôi mới phỏng đoán được ý nghĩa của đoạn sArray(i, 4) = Dic.Item(CStr(sArray(i, 2))) nhưng chưa biết chính xác của nó "dịch ra" nghĩa là thế nào? Xin trợ giúp để tôi có thể hiểu hơn.

Xin trân trọng cảm ơn.
 
Upvote 0
Tôi mới phỏng đoán được ý nghĩa của đoạn sArray(i, 4) = Dic.Item(CStr(sArray(i, 2))) nhưng chưa biết chính xác của nó "dịch ra" nghĩa là thế nào? Xin trợ giúp để tôi có thể hiểu hơn.

Xin trân trọng cảm ơn.

Ví dụ cho dễ hiểu
Ta có quy tắc Add Dic như sau: Dic.Add Key, Item ---> Trong nhóm Keys không có em nào trùng (Items sao cũng được)
Mã:
Dic.Add "a", 5
Dic.Add "b", 11
Dic.Add "c", 15
Vậy để truy xuất Item của Key "b", ta dùng Dic.Item("b") ---> Kết quả = 11
Giống VLOOKUP ấy
 
Upvote 0
Cảm ơn bác Ndu nhé, cái Dic của bác quả là độc đáo. Cứ bài toán nào dính đến trích lọc duy nhất thì ta sử dụng Dic là tối ưu nhất rồi.
 
Upvote 0
Baì tập số ...
Cho bảng dữ liệu như hình :
untitled.JPG

Yêu cầu:
1. Cột F: KQ lọc duy nhất danh sách các công ty, Cột G: doanh thu cao nhất của công ty đó.
2. Xử lý dữ liệu hoàn toàn trên mảng nhưng chỉ được sử dụng tối đa 1 mảng, 1 Dic, 1 vòng lặp.
(Tương tự như Consolidate của Excel).

----------------------------------------------
Bổ sung: Mảng chỉ được phép xử dụng (chép, đọc) một lần

File mẫu:
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Baì tập số ...
Yêu cầu:
1. Cột F: KQ lọc duy nhất danh sách các công ty, Cột G: doanh thu cao nhất của công ty đó.
2. Xử lý dữ liệu hoàn toàn trên mảng nhưng chỉ được sử dụng tối đa 1 mảng, 1 Dic, 1 vòng lặp.
(Tương tự như Consolidate của Excel).
File mẫu:
Dhn46 xin nộp bài (trong bài dùng 2 mảng trong đó có 1 mảng để lấy dữ liệu nguồn không biết có được chấp nhận hay không?)
Mã:
Sub Gpe()
Dim i As Long, k As Long, Arr, ArrKq, Dic As Object
Arr = Range("B2:D" & Range("B65536").End(3).Row)
ReDim ArrKq(1 To UBound(Arr, 1), 1 To 2)
MsgBox UBound(Arr)
Set Dic = CreateObject("scripting.dictionary")
With Dic
    For i = 1 To UBound(Arr, 1)
        If Not .exists(Arr(i, 1)) Then
            k = k + 1
            .Add Arr(i, 1), k
            ArrKq(k, 1) = Arr(i, 1)
            ArrKq(k, 2) = Arr(i, 3)
        Else
            If ArrKq(.Item(Arr(i, 1)), 2) < Arr(i, 3) Then ArrKq(.Item(Arr(i, 1)), 2) = Arr(i, 3)
        End If
    Next
End With
[F2].Resize(UBound(ArrKq, 1), 2) = ArrKq
End Sub
 
Upvote 0
Dhn46 xin nộp bài (trong bài dùng 2 mảng trong đó có 1 mảng để lấy dữ liệu nguồn không biết có được chấp nhận hay không?)
Mã:
Sub Gpe()
Dim i As Long, k As Long, Arr, ArrKq, Dic As Object
Arr = Range("B2:D" & Range("B65536").End(3).Row)
ReDim ArrKq(1 To UBound(Arr, 1), 1 To 2)
MsgBox UBound(Arr)
Set Dic = CreateObject("scripting.dictionary")
With Dic
    For i = 1 To UBound(Arr, 1)
        If Not .exists(Arr(i, 1)) Then
            k = k + 1
            .Add Arr(i, 1), k
            ArrKq(k, 1) = Arr(i, 1)
            ArrKq(k, 2) = Arr(i, 3)
        Else
            If ArrKq(.Item(Arr(i, 1)), 2) < Arr(i, 3) Then ArrKq(.Item(Arr(i, 1)), 2) = Arr(i, 3)
        End If
    Next
End With
[F2].Resize(UBound(ArrKq, 1), 2) = ArrKq
End Sub

Khoong hợp lệ, chỉ duy nhất một mảng
 
Upvote 0
Vậy thì sửa lại chút ạ
Mã:
Sub Gpe()
Dim i As Long, k As Long, Arr, Dic As Object
Arr = Range("B2:D" & Range("B65536").End(3).Row)
Set Dic = CreateObject("scripting.dictionary")
With Dic
    For i = 1 To UBound(Arr, 1)
        If Not .exists(Arr(i, 1)) Then
            k = k + 1
            .Add Arr(i, 1), k
            Arr(k, 1) = Arr(i, 1)
            Arr(k, 2) = Arr(i, 3)
        Else
            If Arr(.Item(Arr(i, 1)), 2) < Arr(i, 3) Then Arr(.Item(Arr(i, 1)), 2) = Arr(i, 3)
        End If
    Next
End With
[F2].Resize(k, 2) = Arr
End Sub

1 mảng Arr, 1 Dic, 1 vòng lặp For... Next
 
Lần chỉnh sửa cuối:
Upvote 0
Cũng được nhưng chưa đúng ý đồ của mình lắm. Thôi thêm một ràng buộc nữa: mảng chỉ được phép xử dụng (gán, đọc) một lần
 
Upvote 0
Cũng được nhưng chưa đúng ý đồ của mình lắm. Thôi thêm một ràng buộc nữa: mảng chỉ được phép xử dụng (gán, đọc) một lần
Thất nghiệp, Làm thử cái này xem sao.
PHP:
Dim Dic As Object, Arr(), I As Long, K As Long, Tem As String
Set Dic = CreateObject("Scripting.Dictionary")
Arr = Range([B2], [B65000].End(xlUp)).Resize(, 3).Value
For I = 1 To UBound(Arr, 1)
    Tem = Arr(I, 1)
    If Not Dic.Exists(Tem) Then
        K = K + 1
        Dic.Add Tem, Arr(I, 3)
    Else
        If Dic.Item(Tem) < Arr(I, 3) Then Dic.Item(Tem) = Arr(I, 3)
    End If
Next I
With Application.WorksheetFunction
[F2].Resize(K).Value = .Transpose(Dic.Keys)
[G2].Resize(K).Value = .Transpose(Dic.Items)
End With
Set Dic = Nothing
End Sub
 
Upvote 0
Thất nghiệp, Làm thử cái này xem sao.
PHP:
Dim Dic As Object, Arr(), I As Long, K As Long, Tem As String
Set Dic = CreateObject("Scripting.Dictionary")
Arr = Range([B2], [B65000].End(xlUp)).Resize(, 3).Value
For I = 1 To UBound(Arr, 1)
    Tem = Arr(I, 1)
    If Not Dic.Exists(Tem) Then
        K = K + 1
        Dic.Add Tem, Arr(I, 3)
    Else
        If Dic.Item(Tem) < Arr(I, 3) Then Dic.Item(Tem) = Arr(I, 3)
    End If
Next I
With Application.WorksheetFunction
[F2].Resize(K).Value = .Transpose(Dic.Keys)
[G2].Resize(K).Value = .Transpose(Dic.Items)
End With
Set Dic = Nothing
End Sub

Cảm ơn anh, bây giờ mình tăng độ khó lên một tí: Không cho dùng .Exists của Dictionary nữa. và đó mới là ý đồ của tôi. Định ra bài cho mấy em "trẻ" nhưng toàn cao thủ như anh thì yêu cầu phải cao lên chứ. Ẹc ...ẹc! (Thấy bác Cò đang lấp ló, vào tham gia cho vui và để anh em học hỏi bác)
 
Lần chỉnh sửa cuối:
Upvote 0
- Bài bác Ba Tê vận dụng Dictionary hay quá! Lại học được 1 cái hay nữa rồi.
- @Bác ThanhLanh: Yêu cầu tiếp theo của bài tập không cho dùng .Exists của Dictionary thì ý đồ chủ đạo ở đây là dùng gì nhỉ? Vì dhn46 nghĩ nếu không dùng .Exists của Dictionary thì chỉ cần bỏ if đoạn đó và thêm (On Error Resume Next) là được.
- Bác có thể hướng mọi người theo 1 cách được không ạ?
 
Upvote 0
- Bài bác Ba Tê vận dụng Dictionary hay quá! Lại học được 1 cái hay nữa rồi.
- @Bác ThanhLanh: Yêu cầu tiếp theo của bài tập không cho dùng .Exists của Dictionary thì ý đồ chủ đạo ở đây là dùng gì nhỉ? Vì dhn46 nghĩ nếu không dùng .Exists của Dictionary thì chỉ cần bỏ if đoạn đó và thêm (On Error Resume Next) là được.

Không chơi với Error luôn!
Cố lên!
- Bác có thể hướng mọi người theo 1 cách được không ạ?
Thì Bác Ba làm gần đúng rồi đó.
 
Lần chỉnh sửa cuối:
Upvote 0
- Bài bác Ba Tê vận dụng Dictionary hay quá! Lại học được 1 cái hay nữa rồi.
- @Bác ThanhLanh: Yêu cầu tiếp theo của bài tập không cho dùng .Exists của Dictionary thì ý đồ chủ đạo ở đây là dùng gì nhỉ? Vì dhn46 nghĩ nếu không dùng .Exists của Dictionary thì chỉ cần bỏ if đoạn đó và thêm (On Error Resume Next) là được.
- Bác có thể hướng mọi người theo 1 cách được không ạ?
Nếu không dùng .Exists thì khi xuất hiện 1 key tồn tại sẽ báo lỗi. Ta có thể bẫy lỗi thế này If Error = 0 then... Else ...End If
PS : Đoán vậy thôi chứ chưa thử nữa nha
 
Lần chỉnh sửa cuối:
Upvote 0
Như vậy là vấn đề đã được giải quyết.
Mấu chốt vấn đề ở đây là ở điểm MyDictionary.Add Key, Item :
Item ở đây có thể không là duy nhất nên ta được phép gán các giá trị trong mảng vào
- Nếu tận dụng thêm thuộc tính .Count của dic nữa thì chắc không cần tới biến k

Cảm ơn các bác đã giúp dhn46 biết thêm 1 cái hay
(Ndu096091631 đã có mặt và đây là lần đầu tiên thấy nick này màu xanh =>Smod. Chúc mừng thầy!)
 
Upvote 0
Các bạn thử đi!. Cố lên! (kỳ này mà mình làm sai chắc bị ném đá tơi bời, hic!)
 
Upvote 0
Các bạn thử đi!. Cố lên! (kỳ này mà mình làm sai chắc bị ném đá tơi bời, hic!)
Mình nói rồi chẳng có gì khó cả. Nếu khó quá thì bỏ chạy vậy thôi
Mượn code của anh Bate xài
PHP:
Sub vuivuivui()
Dim Arr(), I As Long, Tem As String
Arr = Range([B2], [B65000].End(xlUp)).Resize(, 3).Value
   With CreateObject("Scripting.Dictionary")
      For I = 1 To UBound(Arr, 1)
          Tem = Arr(I, 1)
          If Error = 0 Then
              Dic.Add Tem, Arr(I, 3)
          Else
              If .Item(Tem) < Arr(I, 3) Then .Item(Tem) = Arr(I, 3)
          End If
      Next I
      [F2].Resize(.Count).Value = Application.Transpose(.Keys)
      [G2].Resize(.Count).Value = Application.Transpose(.Items)
   End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom