Gộp dữ liệu từ nhiều vùng ? (1 người xem)

Liên hệ QC

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

TrungChinhs

Thành viên tích cực
Tham gia
18/2/08
Bài viết
1,475
Được thích
2,470
Nghề nghiệp
Công chức
Nhờ các bạn viết giúp code lọc dữ liệu trong file đính kèm. Dữ liệu nguồn bên sheet Du lieu. Kết quả mong muốn như sheet Ket qua.
Thanks !
 

File đính kèm

Nhờ các bạn viết giúp code lọc dữ liệu trong file đính kèm. Dữ liệu nguồn bên sheet Du lieu. Kết quả mong muốn như sheet Ket qua.
Thanks !

Anh mới thí dụ có 2 trường hợp, trường hợp tên trùng tên thì thế nào? Rồi trường hợp Đất trùng đất thì có cộng dồn số thửa với diện tích hay không?

Chẳng hạn: Cà Văn Bun có mục "Đất chuyên trồng lúa nước" ở trên là 43 ở dưới là 38 vậy có cộng dồn hay không? (Mà tại sao lại 1 người lại có 2 loại đất này nhỉ?)
 
Lần chỉnh sửa cuối:
Upvote 0
Ý của tôi là: dữ liệu của các hộ có tên giống nhau đang ở nhiều nơi, bây giờ cần dồn về một nơi chứ không cộng. Ví dụ có 2 hộ Cà Văn Bun, bên trên có 5 thửa đất, bên dưới có 4 thửa đất bây giờ chuyển về 1 hộ Cà Văn Bun có 9 thửa.
Trước đây tôi dùng phương pháp gán tên chủ hộ cho từng thửa đất ra cột phụ rồi sort theo tên, sau khi thấy các bạn làm bằng phương pháp kết hợp Dic với Arr rất hay nhưng tôi chưa làm được.
 
Upvote 0
Ý của tôi là: dữ liệu của các hộ có tên giống nhau đang ở nhiều nơi, bây giờ cần dồn về một nơi chứ không cộng. Ví dụ có 2 hộ Cà Văn Bun, bên trên có 5 thửa đất, bên dưới có 4 thửa đất bây giờ chuyển về 1 hộ Cà Văn Bun có 9 thửa.
Trước đây tôi dùng phương pháp gán tên chủ hộ cho từng thửa đất ra cột phụ rồi sort theo tên, sau khi thấy các bạn làm bằng phương pháp kết hợp Dic với Arr rất hay nhưng tôi chưa làm được.
Bạn dùng thử code này xem sao:
Mã:
Public Sub GomGom()
    Dim Vung, d, I, K, Gom, A, M, mM, Tach, TachTiep, Kq
    Set d = CreateObject("scripting.dictionary")
    Vung = Range([D5], [D50000].End(xlUp)).Offset(, -2).Resize(, 5)
    ReDim Kq(1 To UBound(Vung), 1 To 4)
        For I = UBound(Vung) To 1 Step -1
            If Vung(I, 1) = "" Then
                Gom = Gom & Vung(I, 2) & ";" & Vung(I, 3) & ";" & Vung(I, 4) & ";" & Vung(I, 5) & ","
            Else
                If Not d.exists(Vung(I, 2)) Then
                    Gom = Vung(I, 2) & "," & Gom
                    d.Add Vung(I, 2), Gom
                    Gom = ""
                Else
                    d.Item(Vung(I, 2)) = d.Item(Vung(I, 2)) & Gom
                    Gom = ""
                End If
            End If
        Next I
            A = d.items
                For I = UBound(A) To 0 Step -1
                    Tach = Split(A(I), ",")
                        K = K + 1
                        Kq(K, 1) = Tach(0)
                            For M = UBound(Tach) - 1 To 1 Step -1
                                TachTiep = Split(Tach(M), ";")
                                K = K + 1
                                Kq(K, 2) = TachTiep(1): Kq(K, 3) = TachTiep(2): Kq(K, 4) = TachTiep(3)
                            Next M
                Next I
    Sheets("Ket qua").[G4].Resize(K, 4) = Kq
End Sub
Lâu quá hông viết nên lọng cọng thật
Thân
 
Upvote 0
Ý của tôi là: dữ liệu của các hộ có tên giống nhau đang ở nhiều nơi, bây giờ cần dồn về một nơi chứ không cộng. Ví dụ có 2 hộ Cà Văn Bun, bên trên có 5 thửa đất, bên dưới có 4 thửa đất bây giờ chuyển về 1 hộ Cà Văn Bun có 9 thửa.
Trước đây tôi dùng phương pháp gán tên chủ hộ cho từng thửa đất ra cột phụ rồi sort theo tên, sau khi thấy các bạn làm bằng phương pháp kết hợp Dic với Arr rất hay nhưng tôi chưa làm được.
Tham khảo thêm code này nhé
Mã:
Sub TonghopDL()
Dim Arr(), ArrKQ(), iItem
Dim i As Long, j As Long, s As Long, m As Long, k As Long
Arr = Sheet1.Range("C5:F" & Sheet1.[D65000].End(3).Row + 1)
    Set Dic = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(Arr)
  If Arr(i, 1) <> "" And Not Dic.Exists(Arr(i, 1)) Then
     Dic.Add Arr(i, 1), ""
  End If
Next
ReDim ArrKQ(1 To UBound(Arr), 1 To UBound(Arr, 2))
For Each iItem In Dic.keys
s = s + 1
ArrKQ(s, 1) = iItem
   For i = 1 To UBound(Arr)
      If Arr(i, 1) = iItem Then
        For m = i + 1 To i + 10
          If Arr(m, 1) <> "" Or m = UBound(Arr) Then GoTo NextI
          s = s + 1
          For j = 2 To UBound(Arr, 2)
            ArrKQ(s, j) = Arr(m, j)
          Next
        Next
      End If
NextI:
   Next
Next
Sheet2.Range("F4").Resize(s, UBound(Arr, 2)).Value = ArrKQ
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Chậm hơn bác Cò rồi!

Chắc có lẽ mình làm rườm rà hơn bác Cò:

PHP:
Sub TongHopHoangTrongNghia()
      Dim c As Long, h As Long, i As Long, j As Long
      Dim k As Long, r As Long, t As Long
      Dim sArray As Variant, HoTen As Variant
      Dim DataArr1 As Variant, DataArr2 As Variant
      Dim DataArray As Variant, Chk As Boolean
      
      r = DuLieu.Range("D65536").End(xlUp).Row
      sArray = DuLieu.Range("C5:F" & r).Value
      
      i = UBound(sArray, 1): j = UBound(sArray, 2)
      
      ReDim DataArr1(1 To i, 1 To 1): k = 0
      
      With CreateObject("Scripting.Dictionary")
            For h = 1 To i
                  HoTen = sArray(h, 1)
                  If Not .Exists(HoTen) And sArray(h, 1) <> "" Then
                        k = k + 1
                        .Add HoTen, k
                        DataArr1(k, 1) = HoTen
                  End If
            Next
      End With
      
      ReDim DataArr2(1 To i, 1 To j)
      For h = 1 To i
            If h = 1 Then
                  DataArr2(h, 1) = sArray(h, 1)
            Else
                  If sArray(h, 2) = "" Then
                        DataArr2(h, 1) = sArray(h, 1)
                  Else
                        DataArr2(h, 1) = DataArr2(h - 1, 1)
                        For c = 2 To j
                              DataArr2(h, c) = sArray(h, c)
                        Next
                  End If
            End If
      Next
      
      ReDim DataArray(1 To i, 1 To j): r = 1
      
      For t = 1 To k
      
            Chk = True
            HoTen = DataArr1(t, 1)
            
            For h = 1 To i
                  If Chk Then
                        If DataArr2(h, 1) = HoTen And DataArr2(h, 2) = "" Then
                              DataArray(r, 1) = HoTen
                              r = r + 1
                              Chk = False
                        End If
                  Else
                        If DataArr2(h, 1) = HoTen And DataArr2(h, 2) <> "" Then
                              DataArray(r, 1) = ""
                              For c = 2 To j
                                    DataArray(r, c) = DataArr2(h, c)
                              Next
                              r = r + 1
                        End If
                  End If
            Next
      Next

      
      KetQua.Range("B:E").ClearContents
      KetQua.Range("B4").Resize(r, j) = DataArray
End Sub
 

File đính kèm

Upvote 0
Kiểm tra thử tốc độ:

Bác Cò / 0.03125000
Bác Cò / 0.01562500
Bác Cò / 0.01562500

Viehoai / 0.01562500
Viehoai / 0.03125000
Viehoai / 0.01562500

Nghia / 0.04687500
Nghia / 0.04687500
Nghia / 0.04687500

Mình thiệt là Ẹc ... Ẹc ...
 
Upvote 0
Kiểm tra thử tốc độ:

Bác Cò / 0.03125000
Bác Cò / 0.01562500
Bác Cò / 0.01562500

Viehoai / 0.01562500
Viehoai / 0.03125000
Viehoai / 0.01562500

Nghia / 0.04687500
Nghia / 0.04687500
Nghia / 0.04687500

Mình thiệt là Ẹc ... Ẹc ...
Dữ liệu có bằng nắm tay mà kiểm tra cái cóc khô gì!
Giả lập cở 20,000 dòng dữ liệu trở lên rồi mới nói chứ
 
Upvote 0
Kiểm tra thử tốc độ:

Bác Cò / 0.03125000
Bác Cò / 0.01562500
Bác Cò / 0.01562500

Viehoai / 0.01562500
Viehoai / 0.03125000
Viehoai / 0.01562500

Nghia / 0.04687500
Nghia / 0.04687500
Nghia / 0.04687500

Mình thiệt là Ẹc ... Ẹc ...
Híc
Nghĩa hơn đứt anh & bạn Viehoai về......độ ổn định rồi mà, cả 3 lần thời gian đều chạy....như nhau ( cái này khó làm lắm à nha )
Nghia / 0.04687500
Nghia / 0.04687500
Nghia / 0.04687500
Nói chứ viết cho chạy thôi, chứ kiểm tra tốc độ thi dữ liệu phải nhiều & ....nắn nót code lại chứ nhỉ
Híc
 
Upvote 0
Em cũng góp vui 1 code, tuy không chạy nhanh như các anh nhưng em cũng ưng ý lắm
PHP:
Sub Tonghop_quanghai()
Dim d As Object, kq(), dl()
Dim i As Long, j As Long, k As Long, x As Byte
Set d = CreateObject("scripting.dictionary")
With Sheets("Du lieu")
   dl = .Range(.[c5], .[f65536].End(3)).Value
End With
ReDim kq(1 To UBound(dl), 1 To 5)
For i = 2 To UBound(dl)
   If dl(i, 1) = "" Then dl(i, 1) = dl(i - 1, 1)
   If Not d.Exists(dl(i, 1)) Then d.Add dl(i, 1), ""
Next
Key = d.keys
For i = 0 To UBound(Key)
   k = k + 1
   kq(k, 1) = i + 1: kq(k, 2) = Key(i)
   For j = 1 To UBound(dl)
      If dl(j, 1) = Key(i) Then
         If dl(j, 2) <> "" Then
            k = k + 1
            For x = 3 To 5
               kq(k, x) = dl(j, x - 1)
            Next
         End If
      End If
   Next
Next
Sheets("Du lieu").[H5].Resize(k, 5) = kq
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Nhờ các bạn viết giúp code lọc dữ liệu trong file đính kèm. Dữ liệu nguồn bên sheet Du lieu. Kết quả mong muốn như sheet Ket qua.
Thanks !

Thêm một cái nữa cho đông vui:
Mã:
Option Base 1
Option Explicit
Sub test()
    Dim arrDulieu(), arrKetqua(), DicHoTen, i, k, j, jj, ten
    Set DicHoTen = CreateObject("Scripting.Dictionary")
    Sheets("Du lieu").Select
    arrDulieu = Sheets("Du lieu").Range([D5], [D65536].End(xlUp)).Offset(, -2).Resize(, 5).Value
    ReDim arrKetqua(UBound(arrDulieu, 1), 5)
    For i = 1 To UBound(arrDulieu, 1)
        If arrDulieu(i, 1) > 0 Then
            If Not DicHoTen.Exists(arrDulieu(i, 2)) Then
                j = j + 1: k = k + 1: jj = j
                DicHoTen.Add arrDulieu(i, 2), jj
                arrKetqua(k, 2) = arrDulieu(i, 2)
            End If
            ten = arrDulieu(i, 2)
        Else
            k = k + 1
            jj = DicHoTen.Item(ten)
            arrKetqua(k, 3) = arrDulieu(i, 3)
            arrKetqua(k, 4) = arrDulieu(i, 4)
            arrKetqua(k, 5) = arrDulieu(i, 5)
        End If
        arrKetqua(k, 1) = jj
    Next
    Sheets("Ket qua").Select
    With Range("A23")
        .Resize(k, 5).Value = arrKetqua
        .Resize(k, 5).Sort Range("A23"), 1
        .Resize(k).ClearContents
    End With
End Sub
 

File đính kèm

Upvote 0
Thêm một cái nữa cho đông vui:
Mã:
Option Base 1
Option Explicit
Sub test()
    Dim arrDulieu(), arrKetqua(), DicHoTen, i, k, j, jj, ten
    Set DicHoTen = CreateObject("Scripting.Dictionary")
    Sheets("Du lieu").Select
    arrDulieu = Sheets("Du lieu").Range([D5], [D65536].End(xlUp)).Offset(, -2).Resize(, 5).Value
    ReDim arrKetqua(UBound(arrDulieu, 1), 5)
    For i = 1 To UBound(arrDulieu, 1)
        If arrDulieu(i, 1) > 0 Then
            If Not DicHoTen.Exists(arrDulieu(i, 2)) Then
                j = j + 1: k = k + 1: jj = j
                DicHoTen.Add arrDulieu(i, 2), jj
                arrKetqua(k, 2) = arrDulieu(i, 2)
            End If
            ten = arrDulieu(i, 2)
        Else
            k = k + 1
            jj = DicHoTen.Item(ten)
            arrKetqua(k, 3) = arrDulieu(i, 3)
            arrKetqua(k, 4) = arrDulieu(i, 4)
            arrKetqua(k, 5) = arrDulieu(i, 5)
        End If
        arrKetqua(k, 1) = jj
    Next
    Sheets("Ket qua").Select
    With Range("A23")
        .Resize(k, 5).Value = arrKetqua
        .Resize(k, 5).Sort Range("A23"), 1
        .Resize(k).ClearContents
    End With
End Sub

Bị lỗi variable not defined.
 
Upvote 0
Bị lỗi variable not defined.

Ai biểu bạn chạy code "Tonghop" chi, hãy bấm Alt & F8 chọn Sub test mà chạy
Sub Tonghop là của chủ topic, có lẽ đang nháp nhưng mình muốn giữ nguyên trạng vậy, thiếu khai báo biến nên bị lỗi bởi câu lệnh Option Explicit trong code của mình.
 
Upvote 0
Vừa qua ngồi test lại tất cả các code của mọi người thì thấy như sau:

Về tốc độ: (đã thử trên 25,600 dòng)
1) Viehoai (chưa đến 1 s)
2) Hoàng Trọng Nghĩa (chưa đến 1 s)
3) Concogia (chạy trên 3 s)

Về phát sinh lỗi:
1) Viehoai
Do xác định một mục tên trong vòng 10 dòng
nên sẽ bị sót nếu mục nào đó hơn 10 dòng


2) Hoàng Trọng Nghĩa
Chưa phát hiện ra lỗi

3) Concogia
Gom chưa hết các chi tiết trong một mục tên
Còn chừa những hàng rỗng


Hôm nay mới cập nhật của Quang Hải:
4) QuangHai
Chưa phát hiện ra lỗi

Vì code ban đầu mình làm lủng củng nên mình đã làm code mới chạy ổn định hơn. Các kiểu điều kiện thông thường tại diễn đàn này đã có nhiều rồi, nay mình nghĩ ra một hướng đi mới đó là xác định điều kiện thông qua biến Boolean.

Các bạn tham khảo và cho ý kiến nhé:

PHP:
Sub TongHopHoangTrongNghiaNew()
    Dim tg As Double: tg = Timer
    
    Dim sArray, DataArr, DataArray, FullName, MyDic As Object, _
        c As Long, h As Long, i As Long, j As Long, k As Long, n As Long, r As Long, t As Long, _
        OutCheck As Boolean, InCheck As Boolean
    
    KetQua.Range("A:E").ClearContents
    sArray = DuLieu.Range("C5:F" & DuLieu.Range("D65536").End(xlUp).Row + 1).Value
    i = UBound(sArray, 1): j = UBound(sArray, 2)
    
    Set MyDic = CreateObject("Scripting.Dictionary")
    For h = 1 To i
        FullName = sArray(h, 1)
        If Not MyDic.Exists(FullName) And FullName <> "" Then MyDic.Add FullName, ""
    Next

    ReDim DataArray(1 To i, 1 To j + 1): r = 1: n = 0
    FullName = MyDic.keys
    For t = 0 To UBound(MyDic.keys)
        OutCheck = True
        For h = 1 To i
            If h = i - 1 Then Exit For
            k = h + 1
            If sArray(h, 1) = FullName(t) And sArray(k, 1) = "" Then
                If OutCheck Then
                    n = n + 1
                    DataArray(r, 1) = n
                    DataArray(r, 2) = FullName(t)
                    OutCheck = False: r = r + 1
                End If
                InCheck = True
            End If
            If InCheck And sArray(k, 1) = "" Then
                For c = 3 To j + 1
                    DataArray(r, c) = sArray(k, c - 1)
                Next
                r = r + 1
            Else
                InCheck = False
            End If
        Next
    Next
    KetQua.Range("A4").Resize(r - 1, j + 1) = DataArray
    KetQua.Range("K65536").End(xlUp).Offset(1).Value = "Nghia / " & Format(Timer - tg, "0.00000000")
    'Debug.Print "Nghia / " & Format(Timer - tg, "0.00000000")
End Sub

Bài của Viehoai có tốc độ nhanh nhất, nhưng xác định dòng chưa thật sự tổng quát (theo cảm tính đặt 10 dòng cho một mục) cho nên chưa thật sự gom hết các mục nếu mục đó hơn 10 dòng.
 

File đính kèm

Upvote 0
Vừa qua ngồi test lại tất cả các code của mọi người thì thấy như sau:

Về phát sinh lỗi:
1) Viehoai
Do xác định một mục tên trong vòng 10 dòng
nên sẽ bị sót nếu mục nào đó hơn 10 dòng


Bài của Viehoai có tốc độ nhanh nhất, nhưng xác định dòng chưa thật sự tổng quát (theo cảm tính đặt 10 dòng cho một mục) cho nên chưa thật sự gom hết các mục nếu mục đó hơn 10 dòng.
TRong code có dòng lệnh For m = i + 1 To i + 10 nên mới thế, nếu thay 10 bằng 1000 thì tốc độ chẳng ảnh hưởng gì, mình thấy không cần thiết thôi
 
Upvote 0
TRong code có dòng lệnh For m=i+1 to m+10 nên mới thế, nếu thay 10 bằng 1000 thì tốc độ chẳng ảnh hưởng gì, mình thấy không cần thiết thôi

Mình biết là Viehoai thêm tại đó, nhưng nó như chưa tổng quát lắm, thêm bao nhiêu, bớt bao nhiêu thì ai mà lường trước được dữ liệu của một mục đây? Còn nếu thêm nhiều quá vòng lặp sẽ chạy chậm lại do phải lặp đi lặp lại For m nên sẽ chạy chậm ít nhiều.
 
Upvote 0
Mình biết là Viehoai thêm tại đó, nhưng nó như chưa tổng quát lắm, thêm bao nhiêu, bớt bao nhiêu thì ai mà lường trước được dữ liệu của một mục đây? Còn nếu thêm nhiều quá vòng lặp sẽ chạy chậm lại do phải lặp đi lặp lại For m nên sẽ chạy chậm ít nhiều.
Không đúng, mình lặp lại vòng lệnh For.. next:
Mã:
For m = i + 1 To i + 10
     If Arr(m, 1) <> "" Or m = UBound(Arr) Then GoTo NextI
         s = s + 1
         For j = 2 To UBound(Arr, 2)
              ArrKQ(s, j) = Arr(m, j
          Next
      End If
Next
Nghĩa chú ý mình có dòng lệnh: If Arr(m, 1) <> "" Then GoTo NextI nên thay số 10 thành 100000 chẳng ảnh hưởng gì tốc độ
 
Upvote 0
Không đúng, mình lặp lại vòng lệnh For.. next:
Mã:
For m = i + 1 To i + 10
     If Arr(m, 1) <> "" Or m = UBound(Arr) Then GoTo NextI
         s = s + 1
         For j = 2 To UBound(Arr, 2)
              ArrKQ(s, j) = Arr(m, j
          Next
      End If
Next
Nghĩa chú ý mình có dòng lệnh: If Arr(m, 1) <> "" Then GoTo NextI nên thay số 10 thành 100000 chẳng ảnh hưởng gì tốc độ

Nói chung là code của Viehoai và QuangHai chạy tốt và tốc độ rất nhanh, mỗi người có một thuật toán để cho ra kết quả chính xác. Còn code mình thì phát triển theo một hướng khác nên không so với code của 2 bạn được, tuy nhiên về tốc độ cũng không kém các bạn lắm đâu phải không nè!
 
Upvote 0
Trước hết xin lỗi các bạn, do từ hôm qua đến nay bận công việc nên không xem được bài và cũng chưa kịp test.
Tôi rất vui vì đã được các cao thủ về mảng ra tay giúp đỡ. Xin chân thành cảm ơn tất cả các bạn đã tham gia ! Riêng Nghĩa đã giành thêm thời gian kiểm tra các phương án và có thông báo kết quả đối với từng bài. Cảm ơn Nghĩa rất nhiều.
Không hiểu vì sao trận này chỉ thấy Ndu Tọa sơn xem hổ đấu ?
 
Lần chỉnh sửa cuối:
Upvote 0
Anh Nghĩa test cho em Code này nhé. Tks anh!
PHP:
Sub Tonghop()
Dim Arr, sArr
Dim dic As Object
Dim i, k, t As Integer
Arr = Sheet1.Range("C5:F" & Sheet1.[D65000].End(3).Row)
Set dic = CreateObject("Scripting.Dictionary")
ReDim sArr(1 To UBound(Arr, 1), 1 To 4)
' Gan item vao Dic
With dic
For i = 1 To UBound(Arr, 1)
    If Not .exists(Arr(i, 1)) And Arr(i, 1) <> "" Then
        k = k + 1
        .Add Arr(i, 1), k
    ElseIf .exists(Arr(i, 1)) Then
        Arr(i, 2) = 1
    End If
Next
End With
' thay the cot c = " " sang gia tri ben tren
For i = 1 To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next
 ' trich loc
  For Each Item In dic.keys
    For i = 1 To UBound(Arr, 1)
        If Arr(i, 1) = Item And Arr(i, 2) <> 1 Then
            t = t + 1
            sArr(t, 1) = Arr(i, 1)
            sArr(t, 2) = Arr(i, 2)
            sArr(t, 3) = Arr(i, 3)
            sArr(t, 4) = Arr(i, 4)
        End If
    Next
Next
Sheet2.[f4].Resize(UBound(Arr, 1), 4) = sArr
End Sub
 
Upvote 0
Toàn là các ĐẠI CA xuất chiêu hết cả rồi, em làm sao có cơ hội đây?
Ẹc... Ẹc...

Hay tại quả này dễ quá! (nói trúng tim đen luôn)
ndu mà ra tay chắc còn cỡ 10 dòng là xong.
Hic, mà sao code mình đơn giản, dễ điều chỉnh vậy mà không được Nghĩa test nhỉ, "bùn" ghê
 
Upvote 0
Anh Nghĩa test cho em Code này nhé. Tks anh!
PHP:
Sub Tonghop()
Dim Arr, sArr
Dim dic As Object
Dim i, k, t As Integer
Arr = Sheet1.Range("C5:F" & Sheet1.[D65000].End(3).Row)
Set dic = CreateObject("Scripting.Dictionary")
ReDim sArr(1 To UBound(Arr, 1), 1 To 4)
' Gan item vao Dic
With dic
For i = 1 To UBound(Arr, 1)
    If Not .exists(Arr(i, 1)) And Arr(i, 1) <> "" Then
        k = k + 1
        .Add Arr(i, 1), k
    ElseIf .exists(Arr(i, 1)) Then
        Arr(i, 2) = 1
    End If
Next
End With
' thay the cot c = " " sang gia tri ben tren
For i = 1 To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next
 ' trich loc
  For Each Item In dic.keys
    For i = 1 To UBound(Arr, 1)
        If Arr(i, 1) = Item And Arr(i, 2) <> 1 Then
            t = t + 1
            sArr(t, 1) = Arr(i, 1)
            sArr(t, 2) = Arr(i, 2)
            sArr(t, 3) = Arr(i, 3)
            sArr(t, 4) = Arr(i, 4)
        End If
    Next
Next
Sheet2.[f4].Resize(UBound(Arr, 1), 4) = sArr
End Sub

Mình test code của bạn thì phát hiện lỗi chỗ này
i= 1 thì i-1 sẽ =0 nên Arr(0,1) bị lỗi
Mã:
For i = 1 To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next
 
Upvote 0
Vừa hết giờ làm viết vội quá còn lỗi em xin sửa lại chút
Mã:
Sub Tonghop()
Dim Arr, sArr
Dim dic As Object
Dim i, k, t As Integer
Arr = Sheet1.Range("C5:F" & Sheet1.[D65000].End(3).Row)
Set dic = CreateObject("Scripting.Dictionary")
ReDim sArr(1 To UBound(Arr, 1), 1 To 4)
' Gan item vao Dic
With dic
For i = 1 To UBound(Arr, 1)
    If Not .exists(Arr(i, 1)) And Arr(i, 1) <> "" Then
        k = k + 1
        .Add Arr(i, 1), k
    ElseIf .exists(Arr(i, 1)) Then
        Arr(i, 2) = 1
    End If
Next
End With
' thay the cot c = " " sang gia tri ben tren
For i = 1 To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next
'---  trich Loc
  For Each Item In dic.keys
    For i = 1 To UBound(Arr, 1)
        If Arr(i, 1) = Item And Arr(i, 2) = "" Then
            t = t + 1
            sArr(t, 1) = Arr(i, 1)
        ElseIf Arr(i, 1) = Item And Arr(i, 2) <> 1 Then
            t = t + 1
            sArr(t, 2) = Arr(i, 2)
            sArr(t, 3) = Arr(i, 3)
            sArr(t, 4) = Arr(i, 4)
        End If
    Next
Next
Sheet2.[f4].Resize(UBound(Arr, 1), 4) = sArr
End Sub

Mình test code của bạn thì phát hiện lỗi chỗ này
i= 1 thì i-1 sẽ =0 nên Arr(0,1) bị lỗi
Dạ mảng bắt đầu từ "Cà Văn Bó" với ô D5 = "" như vậy khi thay thế giá trị "" dưới "Cà Văn Bó"....bằng "Cà Văn Bó" mới được, như vậy code trên không sai, nếu sai khi và chỉ khi không tồn tại "Cà Văn Bó" đầu tiên (cái này có thể bắt lỗi)
 
Upvote 0
Hay tại quả này dễ quá! (nói trúng tim đen luôn)
ndu mà ra tay chắc còn cỡ 10 dòng là xong.
Hic, mà sao code mình đơn giản, dễ điều chỉnh vậy mà không được Nghĩa test nhỉ, "bùn" ghê

Bây giờ em test giúp Anh nhé!

Thêm một cái nữa cho đông vui:
Mã:
[B]Option Base 1[/B]
Option Explicit
Sub test()
    Dim arrDulieu(), arrKetqua(), DicHoTen, i, k, j, jj, ten
    Set DicHoTen = CreateObject("Scripting.Dictionary")
    [COLOR=#ff0000]Sheets("Du lieu").Select[/COLOR]
    [COLOR=#ff0000]arrDulieu = Sheets("Du lieu").Range([D5], [D65536].End(xlUp)).Offset(, -2).Resize(, 5).Value[/COLOR]
    [B]ReDim arrKetqua(UBound(arrDulieu, 1), 5)[/B]
    For i = 1 To UBound(arrDulieu, 1)
        If arrDulieu(i, 1) > 0 Then
            If Not DicHoTen.Exists(arrDulieu(i, 2)) Then
                j = j + 1: k = k + 1: jj = j
                DicHoTen.Add arrDulieu(i, 2), jj
                arrKetqua(k, 2) = arrDulieu(i, 2)
            End If
            ten = arrDulieu(i, 2)
        Else
            k = k + 1
            jj = DicHoTen.Item(ten)
            arrKetqua(k, 3) = arrDulieu(i, 3)
            arrKetqua(k, 4) = arrDulieu(i, 4)
            arrKetqua(k, 5) = arrDulieu(i, 5)
        End If
        arrKetqua(k, 1) = jj
    Next
[COLOR=#ff0000]    Sheets("Ket qua").Select
    With Range("A23")
        .Resize(k, 5).Value = arrKetqua
        .Resize(k, 5).Sort Range("A23"), 1
        .Resize(k).ClearContents
    End With[/COLOR]
End Sub

Đầu tiên Anh đã chọn Option Base 1 nói nôm na là bắt đầu số thứ tự của mảng lấy từ 1 (nếu thay 1 là 0 thì bắt đầu từ 0). Nhìn vào đó ta biết anh sẽ ghi ReDim arrKetqua(UBound(arrDulieu, 1), 5), nếu ta không đặt nó thì ta cũng có thể ghi ReDim arrKetqua(1 To UBound(arrDulieu, 1), 1 To 5), chỉ nói rộng ra thôi, cái này cũng chẳng ảnh hưởng gì đến code của Anh.

Cách mà code anh chạy dựa vào mục tên và mục số thứ tự để tìm chi tiết, sau đó gán mỗi mục tương ứng với một số thứ tự, rồi sắp xếp lại theo số thứ tự đã gán, cuối cùng xóa đi cột thứ tự.

Theo yêu cầu của chủ topic thì như vậy đã đạt đúng yêu cầu. Tuy nhiên, nếu như chủ topic lại thêm yêu cầu về số thứ tự của một mục, chắc code của anh hơi khó chỉnh sửa lại.

Về thời gian đã test trên 27,000 dòng đã có tốc độ 1.39s, như vậy cũng khá nhanh.

Về thuật toán em xin mạn phép bàn một chút:

Để giảm thời gian chạy ít nhiều trên code, người ta hiếm sử dụng SheetX.Select mà tham chiếu ngay trên địa chỉ Range luôn:

Thay vì:

Mã:
    [COLOR=#ff0000]Sheets("Du lieu").Select[/COLOR]
    arrDulieu = Sheets("Du lieu").Range([D5], [D65536].End(xlUp)).Offset(, -2).Resize(, 5).Value

và:
Mã:
    [COLOR=#ff0000]Sheets("Ket qua").Select[/COLOR]
    With Range("A4")
        .Resize(k, 5).Value = arrKetqua
        .Resize(k, 5).Sort Range("A4"), 1
        .Resize(k).ClearContents
    End With

Thì nên chỉnh lại như vầy:

Mã:
arrDulieu = Range([COLOR=#0000ff]Sheets("Du lieu")[/COLOR].[D5], [COLOR=#0000ff]Sheets("Du lieu")[/COLOR].[D65536].End(xlUp)).Offset(, -2).Resize(, 5).Value

và như vầy:

Mã:
    With Sheets("Ket qua").Range("A4")
        .Resize(k, 5).Value = arrKetqua
        .Resize(k, 5).Sort Range("A4"), 1
        .Resize(k).ClearContents
    End With

Nói chung code của Anh cũng cho tốc độ nhanh và cũng đã đúng yêu cầu của tác giả topic này. Một số ý kiến của em là vậy.
 
Lần chỉnh sửa cuối:
Upvote 0
Với bài này anh em nào có thể giải ra kết quả theo yêu cầu của tác giả mà không dùng dictionary. Chỉ là vui chơi thôi chứ em không dám có ý thách đố nha các anh. Vì cũng khá lâu rồi mới có 1 bài hấp dẫn thế này.
 
Lần chỉnh sửa cuối:
Upvote 0
Vừa hết giờ làm viết vội quá còn lỗi em xin sửa lại chút
Mã:
Sub Tonghop()
Dim Arr, sArr
Dim dic As Object
Dim i, k, t As Integer
Arr = Sheet1.Range("C5:F" & Sheet1.[D65000].End(3).Row)
Set dic = CreateObject("Scripting.Dictionary")
ReDim sArr(1 To UBound(Arr, 1), 1 To 4)
' Gan item vao Dic
With dic
For i = 1 To UBound(Arr, 1)
    If Not .exists(Arr(i, 1)) And Arr(i, 1) <> "" Then
        k = k + 1
        .Add Arr(i, 1), k
    ElseIf .exists(Arr(i, 1)) Then
        Arr(i, 2) = 1
    End If
Next
End With
' thay the cot c = " " sang gia tri ben tren
For i = 1 To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next
'---  trich Loc
  For Each Item In dic.keys
    For i = 1 To UBound(Arr, 1)
        If Arr(i, 1) = Item And Arr(i, 2) = "" Then
            t = t + 1
            sArr(t, 1) = Arr(i, 1)
        ElseIf Arr(i, 1) = Item And Arr(i, 2) <> 1 Then
            t = t + 1
            sArr(t, 2) = Arr(i, 2)
            sArr(t, 3) = Arr(i, 3)
            sArr(t, 4) = Arr(i, 4)
        End If
    Next
Next
Sheet2.[f4].Resize(UBound(Arr, 1), 4) = sArr
End Sub


Dạ mảng bắt đầu từ "Cà Văn Bó" với ô D5 = "" như vậy khi thay thế giá trị "" dưới "Cà Văn Bó"....bằng "Cà Văn Bó" mới được, như vậy code trên không sai, nếu sai khi và chỉ khi không tồn tại "Cà Văn Bó" đầu tiên (cái này có thể bắt lỗi)

Bạn QuangHai đã nói đúng, hình như bạn chưa sửa được vấn đề này:

Mã:
' thay the cot c = " " sang gia tri ben tren
For i = 1 To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next

Về nguyên tắc, với i = 1 mà Arr(i - 1, 1) thì code này đã bị lỗi ngay "vòng giữ xe" rồi! Nên code này chỉ cần sửa lại đơn giản như sau:

Mã:
For i = [COLOR=#ff0000][B]2[/B][/COLOR] To UBound(Arr, 1)
    If Arr(i, 1) = "" Then
        Arr(i, 1) = Arr(i - 1, 1)
    End If
Next

Về thời gian test thử trên 27000 dòng với 3 lần chạy thử (sau khi sửa lại 1 thành 2) thì thời gian chạy khoảng 1.6s.
 
Upvote 0
Với bài này anh em nào có thể giải ra kết quả theo yêu cầu của tác giả mà không dùng dictionary. Chỉ là vui chơi thôi chứ em không dám có ý thách đố nha các anh. Vì cũng khá lâu rồi mới có 1 bài hấp dẫn thế này.

Vấn đề này chỉ có chép ra một cột phụ rồi sort lại theo thứ tự, từ đó lọc trên mảng thôi. Không biết QuangHai có còn cách nào khác không?
 
Upvote 0
Vấn đề này chỉ có chép ra một cột phụ rồi sort lại theo thứ tự, từ đó lọc trên mảng thôi. Không biết QuangHai có còn cách nào khác không?
Mình giải thế này, xử lý tại vùng dữ liệu gốc luôn. Tuy có hơi chậm hơn cách có dictionary nhưng cũng không nhiều lắm

PHP:
Sub Tonghop_No_Dic()
Dim dl(), i As Long, kq(), j As Long, k As Long, n As Long
With Sheets("Du lieu")
   dl = .Range(.[C5], .[D65536].End(3).Offset(, 2)).Value
   For i = 2 To UBound(dl)
      If dl(i, 1) = "" Then dl(i, 1) = dl(i - 1, 1)
   Next
   .[C5].Resize(UBound(dl), 4) = dl
   .Range(.[C5], .[D65536].End(3).Offset(, 2)).Sort key1:=.[C3]
   dl = .Range(.[C5], .[D65536].End(3).Offset(, 2)).Value
   For i = UBound(dl) To 2 Step -1
      If dl(i, 1) = dl(i - 1, 1) Then dl(i, 1) = Empty
   Next
   .[C5].Resize(UBound(dl), 4) = dl
   ReDim kq(1 To UBound(dl), 1 To 5)
   For i = 1 To UBound(dl)
      If dl(i, 1) <> "" Or dl(i, 2) <> "" Then
         k = k + 1
         If dl(i, 2) = "" Then
            n = n + 1: kq(k, 1) = n
         End If
         For j = 2 To 5
            kq(k, j) = dl(i, j - 1)
         Next
      End If
   Next
   .[B5].Resize(UBound(dl), 5) = kq
End With
End Sub
 
Upvote 0
Mình giải thế này, xử lý tại vùng dữ liệu gốc luôn. Tuy có hơi chậm hơn cách có dictionary nhưng cũng không nhiều lắm

Mã:
Sub Tonghop_No_Dic()
Dim dl(), i As Long, kq(), j As Long, k As Long, n As Long
With Sheets("Du lieu")
   dl = .Range(.[C5], .[D65536].End(3).Offset(, 2)).Value
   For i = 2 To UBound(dl)
      If dl(i, 1) = "" Then dl(i, 1) = dl(i - 1, 1)
   Next
   .[C5].Resize(UBound(dl), 4) = dl
   [COLOR=#ff0000][B].Range(.[C5], .[D65536].End(3).Offset(, 2)).Sort key1:=.[C3][/B][/COLOR]
   dl = .Range(.[C5], .[D65536].End(3).Offset(, 2)).Value
   For i = UBound(dl) To 2 Step -1
      If dl(i, 1) = dl(i - 1, 1) Then dl(i, 1) = Empty
   Next
   .[C5].Resize(UBound(dl), 4) = dl
   ReDim kq(1 To UBound(dl), 1 To 5)
   For i = 1 To UBound(dl)
      If dl(i, 1) <> "" Or dl(i, 2) <> "" Then
         k = k + 1
         If dl(i, 2) = "" Then
            n = n + 1: kq(k, 1) = n
         End If
         For j = 2 To 5
            kq(k, j) = dl(i, j - 1)
         Next
      End If
   Next
   .[B5].Resize(UBound(dl), 5) = kq
End With
End Sub

Mình đã nói rồi, không dùng Sort thì không giải quyết được vấn đề về lọc duy nhất đâu!
 
Upvote 0
Rất vui mừng vì bài mình cuôí cùng cũng được "chấm", cảm ơn Hoàng Trọng Nghĩa. Bây giờ cứ xem như mình là trò đang lên thớt và phản biện nhé.


Bây giờ em test giúp Anh nhé!
Đầu tiên Anh đã chọn Option Base 1 nói nôm na là bắt đầu số thứ tự của mảng lấy từ 1 (nếu thay 1 là 0 thì bắt đầu từ 0). Nhìn vào đó ta biết anh sẽ ghi ReDim arrKetqua(UBound(arrDulieu, 1), 5), nếu ta không đặt nó thì ta cũng có thể ghi ReDim arrKetqua(1 To UBound(arrDulieu, 1), 1 To 5), chỉ nói rộng ra thôi, cái này cũng chẳng ảnh hưởng gì đến code của Anh.
Cái này chỉ là thói quen thôi (mình thống nhất với ... mình vậy rồi), để đề phòng bất trắc xảy ra, vì trong module của mình nhiều khi không phải là một mảng mà có thể nhiều mảng nên trên đầu module nào có mảng mình luôn dể câu Option Base 1. Vì vậy, có khi trước một mảng mình khai báo là ReDim arrABC(1 To 10, 1 To 5) nhưng trên đầu module của mình vẫn có câu Option Base 1 do quên không xóa nhưng vô hại.


Theo yêu cầu của chủ topic thì như vậy đã đạt đúng yêu cầu. Tuy nhiên, nếu như chủ topic lại thêm yêu cầu về số thứ tự của một mục, chắc code của anh hơi khó chỉnh sửa lại.
Nếu muốn có STT thì có nhiều cách, nhưng làm sao không phải thêm vòng lặp nữa để khổi ảnh hưởng tốc độ. Không gì khó cả, đã có vòng lặp sẵn rồi, tạo thêm một mảng một cột lấy STT đồng thời với việc tạo mảng kết quả khi chạy vòng lặp đó. Có mảng TT rồi, khi gán mảng kết quả và sort xong ta gán mảng này luôn. Mình thích thuật toán này vì chỉ dùng có một vòng lăp cho cả sub.

Về thuật toán em xin mạn phép bàn một chút:

Để giảm thời gian chạy ít nhiều trên code, người ta hiếm sử dụng SheetX.
Select mà tham chiếu ngay trên địa chỉ Range luôn
Ờ, cũng là do thói quen thôi, khi code ít di chuyển qua lại giữa các Sheet thì mình luôn làm vậy để dùng cho các câu lệnh khác luôn, ở đây chỉ có hai lần chọn Sheet nên mình nghĩ là không sao.
 
Upvote 0
Rất vui mừng vì bài mình cuôí cùng cũng được "chấm", cảm ơn Hoàng Trọng Nghĩa. Bây giờ cứ xem như mình là trò đang lên thớt và phản biện nhé.


Cái này chỉ là thói quen thôi (mình thống nhất với ... mình vậy rồi), để đề phòng bất trắc xảy ra, vì trong module của mình nhiều khi không phải là một mảng mà có thể nhiều mảng nên trên đầu module nào có mảng mình luôn dể câu Option Base 1. Vì vậy, có khi trước một mảng mình khai báo là ReDim arrABC(1 To 10, 1 To 5) nhưng trên đầu module của mình vẫn có câu Option Base 1 do quên không xóa nhưng vô hại.

Nếu muốn có STT thì có nhiều cách, nhưng làm sao không phải thêm vòng lặp nữa để khổi ảnh hưởng tốc độ. Không gì khó cả, đã có vòng lặp sẵn rồi, tạo thêm một mảng một cột lấy STT đồng thời với việc tạo mảng kết quả khi chạy vòng lặp đó. Có mảng TT rồi, khi gán mảng kết quả và sort xong ta gán mảng này luôn. Mình thích thuật toán này vì chỉ dùng có một vòng lăp cho cả sub.

Ờ, cũng là do thói quen thôi, khi code ít di chuyển qua lại giữa các Sheet thì mình luôn làm vậy để dùng cho các câu lệnh khác luôn, ở đây chỉ có hai lần chọn Sheet nên mình nghĩ là không sao.

Khi chọn qua một sheet khác, nếu sheet này có đặt 2 sự kiện:

PHP:
Private Sub Worksheet_Activate()

End Sub

Private Sub Worksheet_Deactivate()

End Sub

Thì các sự kiện này sẽ chạy, chắc anh không muốn chúng nó chạy khi anh đang chạy code chứ? Vì vậy tốt hơn hết ta đừng Select sheet gì cả.
 
Upvote 0
Mình đã nói rồi, không dùng Sort thì không giải quyết được vấn đề về lọc duy nhất đâu!
Vậy là như thế nào anh Nghĩa, nếu tác động trục tiếp trên cell thì vẫn có cách trích lọc duy nhất mà.
PHP:
Sub Th()
Dim Arr, Dl
Dim i, k As Integer
With Sheet1
Dl = .Range("c5:f" & [f65536].End(xlUp).Row)
ReDim Arr(1 To UBound(Dl), 1 To 4)
For i = 1 To [f65536].End(xlUp).Row
    If Cells(i + 2, 3) <> "" And Application.WorksheetFunction.CountIf(Range(Cells(5, 3), Cells(i + 2, 3)), Cells(i + 2, 3)) = 1 Then
                k = k + 1
                Arr(k, 1) = Cells(i + 2, 3)
    End If
Next
End With
End Sub
 
Upvote 0
Vậy là như thế nào anh Nghĩa, nếu tác động trục tiếp trên cell thì vẫn có cách trích lọc duy nhất mà.
PHP:
Sub Th()
Dim Arr, Dl
Dim i, k As Integer
With Sheet1
Dl = .Range("c5:f" & [f65536].End(xlUp).Row)
ReDim Arr(1 To UBound(Dl), 1 To 4)
For i = 1 To [f65536].End(xlUp).Row
    If Cells(i + 2, 3) <> "" And Application.WorksheetFunction.CountIf(Range(Cells(5, 3), Cells(i + 2, 3)), Cells(i + 2, 3)) = 1 Then
                k = k + 1
                Arr(k, 1) = Cells(i + 2, 3)
    End If
Next
End With
End Sub
Đúng rồi, còn thêm phương án dùng advancefilter trích lọc duy nhất và sau đó có thể không dùng Dic.
 
Upvote 0
Mình đã nói rồi, không dùng Sort thì không giải quyết được vấn đề về lọc duy nhất đâu!
Híc, cái này hình như không chính xác lắm, lúc trước chưa biết sử dụng em "Đít To" thì cũng có cả đống cách giải quyết duy nhất cơ mà
Với đề bài này, nếu không cho sử dụng Dic, Sort, Mảng, Bộ Lọc vẫn có thể giải quyết được ( dĩ nhiên code nó rườm ra & tốc độ thì "xi-ma-chao", hihi)
Trong bài chỉ là một trong nhiều cách giải xử lý hoàn toàn trên sheet ( cứ Ạc, Ạc mãi cũng chán)
Híc
 

File đính kèm

Upvote 0
Bây giờ, trên file này tôi gửi lên, bạn nào Không dùng Dictionary, không dùng AvancedFilter chỉ xử lý trên mảng thì đưa lên phương án.

Cách của tôi:

PHP:
Sub HTN_UniqueOnly_Sort()
    Dim h As Long, i As Long, r As Long
    Dim sArray, UnqArr, sItem As String
    With Sheet1.Range("BB1:BB60")
        .Value = Sheet1.Range("A1:A60").Value
        .Sort Sheet1.[BB1], 1
         sArray = .Value
        .Clear
    End With
    i = UBound(sArray, 1): r = 0: sItem = ""
    ReDim UnqArr(1 To i, 1 To 1)
    For h = 1 To i
        If sArray(h, 1) <> "" And sArray(h, 1) <> sItem Then
            r = r + 1
            UnqArr(r, 1) = sArray(h, 1)
        End If
        sItem = sArray(h, 1)
    Next
    Sheet1.Range("J3").Resize(r).Value = UnqArr
End Sub
 

File đính kèm

Upvote 0
Bây giờ, trên file này tôi gửi lên, bạn nào Không dùng Dictionary, không dùng AvancedFilter chỉ xử lý trên mảng thì đưa lên phương án.

Cách của tôi:

PHP:
Sub HTN_UniqueOnly_Sort()
    Dim h As Long, i As Long, r As Long
    Dim sArray, UnqArr, sItem As String
    With Sheet1.Range("BB1:BB60")
        .Value = Sheet1.Range("A1:A60").Value
        .Sort Sheet1.[BB1], 1
         sArray = .Value
        .Clear
    End With
    i = UBound(sArray, 1): r = 0: sItem = ""
    ReDim UnqArr(1 To i, 1 To 1)
    For h = 1 To i
        If sArray(h, 1) <> "" And sArray(h, 1) <> sItem Then
            r = r + 1
            UnqArr(r, 1) = sArray(h, 1)
        End If
        sItem = sArray(h, 1)
    Next
    Sheet1.Range("J3").Resize(r).Value = UnqArr
End Sub

Hic anh Nghĩa ơi bài toán này mình xử lý không tới 10 dòng lệnh đấy nhé
Chắc anh không nhớ là những chiêu này mình học của anh đấy.

Mã:
Sub loc_khong_trung_quanghai()
Dim dl(), tim As Object, i As Long
dl = Range([A1], [a65536].End(3)).Value
For i = 1 To UBound(dl)
   Set tim = Range("J:J").Find(dl(i, 1))
   If tim Is Nothing Then [J65536].End(3).Offset(1) = dl(i, 1)
Next
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Một cách nữa
Mã:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Tach
    Vung = Range([A1], [A10000].End(xlUp))
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll) = 0 Then Kq = Kq & Cll & ","
            End If
        Next Cll
    Tach = Split(Kq, ",")
[B1].Resize(UBound(Tach)) = Application.WorksheetFunction.Transpose(Tach)
End Sub
Híc, Dzui
 
Upvote 0
Một cách nữa
Mã:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Tach
    Vung = Range([A1], [A10000].End(xlUp))
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll) = 0 Then Kq = Kq & Cll & ","
            End If
        Next Cll
    Tach = Split(Kq, ",")
[B1].Resize(UBound(Tach)) = Application.WorksheetFunction.Transpose(Tach)
End Sub
Híc, Dzui

Cách của anh Cò thật độc đáo, nhưng chưa đúng anh ơi. Giả sử có Chuỗi Hoàng Trọng nằm khoảng giữa trong vùng dữ liệu thì code anh tèo rồi.. hic
 
Upvote 0
Hic anh Nghĩa ơi bài toán này mình xử lý không tới 10 dòng lệnh đấy nhé
Chắc anh không nhớ là những chiêu này mình học của anh đấy.

Mã:
Sub loc_khong_trung_quanghai()
Dim dl(), tim As Object, i As Long
dl = Range([A1], [a65536].End(3)).Value
For i = 1 To UBound(dl)
   Set tim = Range("J:J").Find(dl(i, 1))
   If tim Is Nothing Then [J65536].End(3).Offset(1) = dl(i, 1)
Next
End Sub

Mình đang nói thử trên mảng thôi trời ạ! Đang cố gắng không động tới sheet mà chưa được nè! Cái nãy còn đụng tới ông Sort nên chưa hài lòng.
 
Upvote 0
Nhìn vế 2 chữ ký của Nghĩa nên mình góp code này:

Mã:
Sub Test()
Dim Tm, Kq()
Tm = Sheet1.[A1:A60]
ReDim Kq(1)
For i = 1 To UBound(Tm, 1)
If InStr(1, Join(Kq, ";"), Tm(i, 1)) = 0 Then
Kq(UBound(Kq) - 1) = Tm(i, 1)
ReDim Preserve Kq(UBound(Kq) + 1)
End If
Next
Sheet1.[j3].Resize(UBound(Kq) + 1) = _
WorksheetFunction.Transpose(Kq)
End Sub
 
Upvote 0
Nhìn vế 2 chữ ký của Nghĩa nên mình góp code này:

Mã:
Sub Test()
Dim Tm, Kq()
Tm = Sheet1.[A1:A60]
ReDim Kq(1)
For i = 1 To UBound(Tm, 1)
If InStr(1, Join(Kq, ";"), Tm(i, 1)) = 0 Then
Kq(UBound(Kq) - 1) = Tm(i, 1)
ReDim Preserve Kq(UBound(Kq) + 1)
End If
Next
Sheet1.[j3].Resize(UBound(Kq) + 1) = _
WorksheetFunction.Transpose(Kq)
End Sub

Hay thiệt đó nha! Ngắn gọn mà hiệu quả! Tốc độ nhanh chóng!
 
Upvote 0
Cách của anh Cò thật độc đáo, nhưng chưa đúng anh ơi. Giả sử có Chuỗi Hoàng Trọng nằm khoảng giữa trong vùng dữ liệu thì code anh tèo rồi.. hic
Hihi, sửa tí _ cái này bị hoài mà chẳng nhớ. Híc
Mã:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Tach
    Vung = Range([A1], [A10000].End(xlUp))
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll & ",") = 0 Then Kq = Kq & Cll & ","
            End If
        Next Cll
    Tach = Split(Kq, ",")
[B1].Resize(UBound(Tach)) = Application.WorksheetFunction.Transpose(Tach)
End Sub
Có thể tạo mảng gán kết quả luôn cũng được
 
Upvote 0
Mình mượn code của Bác Cò rồi bỏ cái WorkSheetFunction đi thay vào đó một vòng lặp nữa để không lệ thuộc vào hàm của sheet:

PHP:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Tach, KetQua, i As Long
    Vung = Range([A1], [A10000].End(xlUp))
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll & ",") = 0 Then Kq = Kq & Cll & ","
            End If
        Next Cll
    Tach = Split(Kq, ",")
    
    ReDim KetQua(1 To UBound(Tach), 1 To 1)
    For i = 1 To UBound(Tach)
        KetQua(i, 1) = Tach(i - 1)
    Next
    
    [B1].Resize(UBound(Tach)) = KetQua
End Sub
 
Upvote 0
Cho em góp vui với
Mã:
Sub duynhat()
Dim arr, sarr
Dim i, j, k As Integer
arr = Range([A1], [A10000].End(xlUp))
ReDim sarr(1 To UBound(arr, 1), 1 To 1)
For i = 1 To UBound(arr)
    For j = i + 1 To UBound(arr)
        If arr(j, 1) = arr(i, 1) Then
            arr(j, 1) = ""
        End If
    Next
Next


For i = 1 To UBound(arr, 1)
    If arr(i, 1) <> "" Then
        k = k + 1
        sarr(k, 1) = arr(i, 1)
    End If
Next
  [B1].Resize(UBound(sarr)) = sarr
End Sub
 
Upvote 0
Cho em góp vui với
Mã:
Sub duynhat()
Dim arr, sarr
Dim i, j, k As Integer
arr = Range([A1], [A10000].End(xlUp))
ReDim sarr(1 To UBound(arr, 1), 1 To 1)
For i = 1 To UBound(arr)
    For j = i + 1 To UBound(arr)
        If arr(j, 1) = arr(i, 1) Then
            arr(j, 1) = ""
        End If
    Next
Next


For i = 1 To UBound(arr, 1)
    If arr(i, 1) <> "" Then
        k = k + 1
        sarr(k, 1) = arr(i, 1)
    End If
Next
  [B1].Resize(UBound(sarr)) = sarr
End Sub
Code này sẽ chạy rất chậm nếu xử lý dữ liệu nhiều, nếu dữ liệu 20 000 dòng thì tức là 20 000 X 20 000 = 400 000 000

For i = 1 To UBound(arr)
For j = i + 1 To UBound(arr)
Khả năng treo máy có thể xảy ra. >>> Code này chắc không được rồi
 
Upvote 0
Mình đang nói thử trên mảng thôi trời ạ! Đang cố gắng không động tới sheet mà chưa được nè! Cái nãy còn đụng tới ông Sort nên chưa hài lòng.

Vậy được không, chạy với dữ liệu của Nghĩa, xử lý trên Array (noDic)
Mã:
Option Base 1
Sub Test_noDic()
    Dim tg As Double: tg = Timer
    Dim arrDulieu(), arrKetqua(), i, k, j, jj, arrOnly(), x, kt, TT
    arrDulieu = Range(Sheets("Du lieu").[J5], Sheets("Du lieu").[J65536].End(xlUp)).Offset(, -2).Resize(, 5).Value
    ReDim arrKetqua(UBound(arrDulieu, 1), 5)
    For i = 1 To UBound(arrDulieu, 1)
        If arrDulieu(i, 2) <> "" Then
            kt = 0
            If k > 1 Then
                For x = 1 To UBound(arrOnly, 2)
                    If arrDulieu(i, 2) = arrOnly(2, x) Then kt = 1: TT = arrOnly(1, x)
                Next
            End If
            If kt = 0 Then    'ten chua co trong danh sach
                j = j + 1: k = k + 1: jj = j
                ReDim Preserve arrOnly(1 To 2, jj)
                arrOnly(1, jj) = jj: arrOnly(2, jj) = arrDulieu(i, 2)
                arrKetqua(k, 2) = arrDulieu(i, 2)
            End If
        Else
            k = k + 1
            If kt = 1 Then jj = TT
            arrKetqua(k, 3) = arrDulieu(i, 3)
            arrKetqua(k, 4) = arrDulieu(i, 4)
            arrKetqua(k, 5) = arrDulieu(i, 5)
        End If
        arrKetqua(k, 1) = jj
    Next
    With Sheets("Ket qua").Range("A4")
        .Resize(k, 5).Value = arrKetqua
        .Resize(k, 5).Sort Sheets("Ket qua").Range("A4"), 1
    End With
    Dim arrTT()
    arrTT = Sheets("Ket qua").Range("A4").Resize(k, 2).Value
    For i = 1 To UBound(arrTT, 1)
        If arrTT(i, 2) = "" Then arrTT(i, 1) = ""
    Next
    Sheets("Ket qua").Range("A4").Resize(k, 2).Value = arrTT
    MsgBox Format(Timer - tg, "0.00000000")
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Mình mượn code của Bác Cò rồi bỏ cái WorkSheetFunction đi thay vào đó một vòng lặp nữa để không lệ thuộc vào hàm của sheet:

PHP:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Tach, KetQua, i As Long
    Vung = Range([A1], [A10000].End(xlUp))
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll & ",") = 0 Then Kq = Kq & Cll & ","
            End If
        Next Cll
    Tach = Split(Kq, ",")
    
    ReDim KetQua(1 To UBound(Tach), 1 To 1)
    For i = 1 To UBound(Tach)
        KetQua(i, 1) = Tach(i - 1)
    Next
    
    [B1].Resize(UBound(Tach)) = KetQua
End Sub
Má ơi, đã tạo mảng gán kết quả thì ......gán luôn lúc phát hiện cell nào là duy nhất, sao lại phải thêm vòng lặp chi nữa
Mã:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Mg, K
    Vung = Range([A1], [A10000].End(xlUp))
    ReDim Mg(1 To UBound(Vung), 1 To 1)
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll & ",") = 0 Then
                    K = K + 1
                    Kq = Kq & Cll & ","
                    Mg(K, 1) = Cll
                End If
            End If
        Next Cll
   [B1].Resize(K) = Mg
End Sub
Híc
 
Upvote 0
Má ơi, đã tạo mảng gán kết quả thì ......gán luôn lúc phát hiện cell nào là duy nhất, sao lại phải thêm vòng lặp chi nữa
Mã:
Public Sub DuyNhat()
    Dim Vung, Kq, Cll, Mg, K
    Vung = Range([A1], [A10000].End(xlUp))
    ReDim Mg(1 To UBound(Vung), 1 To 1)
        For Each Cll In Vung
            If Cll <> "" Then
                If InStr(1, Kq, Cll & ",") = 0 Then
                    K = K + 1
                    Kq = Kq & Cll & ","
                    Mg(K, 1) = Cll
                End If
            End If
        Next Cll
   [B1].Resize(K) = Mg
End Sub
Híc

Đúng vậy, với cách này em nghĩ có thể làm một mảng với nhiều cột đúng không?
 
Upvote 0
Theo tôi với dạng bài này thì có Dic rồi sao không sử dụng cho nhanh mà mất công tư duy.
Tôi thấy code của anh ThanhLanh là hợp lý nhất, gán cho cái số TT và sort cho khỏe.
Trường hợp bài này nếu bổ sung thêm dòng công SubTotal trên đầu để cộng DT thì triển khai thêm thế nào.

Nếu dùng Dic và không dùng sort thì theo tôi bài dạng này cần phải 2 for i mới OK.
 
Upvote 0
Theo mình tất cả các động tác sử lý trực tiếp trên bảng tính đều chậm rất nhiều lần, nếu dữ liệu lớn thì hậu quả nhỡn tiền.
Kể cả bài trước chỉ là ý tưởng thôi, chứ sẽ lỗi nhiều nhất là mảng kq lớn vượt giới hạn biến chuỗi cũng không ổn. Theo mình nên thế này cho nó lành:

Mã:
Sub Test()
Dim Kt As Boolean, Tm, Kq(), i, j
Tm = Sheet1.[A1:A60]
ReDim Kq(1)
For i = 1 To UBound(Tm, 1)
Kt = True
For j = 0 To UBound(Kq)
If Tm(i, 1) = Kq(j) Then
Kt = False: Exit For
End If
Next
If Kt Then
Kq(UBound(Kq) - 1) = Tm(i, 1)
ReDim Preserve Kq(UBound(Kq) + 1)
End If
Next
Sheet1.[j3].Resize(UBound(Kq) + 1) = _
WorksheetFunction.Transpose(Kq)
End Sub
 
Upvote 0
Theo tôi với dạng bài này thì có Dic rồi sao không sử dụng cho nhanh mà mất công tư duy.
Tôi thấy code của anh ThanhLanh là hợp lý nhất, gán cho cái số TT và sort cho khỏe.
Trường hợp bài này nếu bổ sung thêm dòng công SubTotal trên đầu để cộng DT thì triển khai thêm thế nào.

Nếu dùng Dic và không dùng sort thì theo tôi bài dạng này cần phải 2 for i mới OK.

Chắc anh chưa xem những giải pháp ở những trang đầu, tất cả có dùng Dictionary cả. Tuy nhiên bắt đầu từ bài 29 của QuangHai mọi người mới "mất công tư duy" cho vui.

Với bài này anh em nào có thể giải ra kết quả theo yêu cầu của tác giả mà không dùng dictionary. Chỉ là vui chơi thôi chứ em không dám có ý thách đố nha các anh. Vì cũng khá lâu rồi mới có 1 bài hấp dẫn thế này.

Nhưng đâu phải không có ích đâu, nó làm cho bộ não mình vận động, tìm hướng đi mới mẽ, rút ra những kinh nghiệm, những bài học từ suy luận của chính bản thân mình, rồi so sánh thiệt hơn, rồi chọn lựa những cách hiệu quả nhất, hơn là copy những cái có sẳn rồi áp dụng, ý kiến của em là như vậy.
 
Upvote 0

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

Back
Top Bottom