Các câu hỏi về mảng trong VBA (Array)

Liên hệ QC

viehoai

Thành viên gắn bó
Tham gia
22/5/09
Bài viết
2,599
Được thích
2,908
Xin các anh chị giúp đỡ Code Gán các giá trị của một Range là các phần tử của Mãng
Ví dụ: Tôi có các giá trị của Range("A1:A10"). Tôi muốn viết code để gán giá trị của các cells từ A1:A10 là các phần tử của Mãng Arr chẳn hạn.
Xin cảm ơn các anh chị
 
Em vẫn còn chưa rõ một số khái niệm về mảng 1 chiều và 2 chiều

Code này em chạy không có vấn đề gì

PHP:
Function UniqueList(sArray)
    Dim SubArr, Item
    SubArr = sArray
    Set Dic = CreateObject("Scripting.Dictionary")
    For Each Item In SubArr
        If Item <> "" And Not Dic.Exists(Item) Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()
    Dim Tmp()
    Tmp = UniqueList(Sheet1.Range("A1:B50000"))
    ReDim Arr(1 To UBound(Tmp, 1) + 1, 1 To 1)
    For i = 0 To UBound(Tmp, 1)
        Arr(i + 1, 1) = Tmp(i)
    Next
    Sheets("Sheet2").[A1].Resize(i) = Arr
End Sub

Nhưng em thử thay 2 dòng

PHP:
Dim SubArr
Arr(i + 1, 1) = Tmp(i)

bằng
PHP:
Dim SubArr()
Arr(i + 1, 1) = Tmp(i,1)
thì bị lỗi ngay

--------------
Vì em vẫn nghĩ: Tmp(i)=Tmp(i,1)
SubArr là mảng thì khi khai báo Dim SubArr() và Dim SubArr có gì khác nhau ah?
 
Upvote 0
Em vẫn còn chưa rõ một số khái niệm về mảng 1 chiều và 2 chiều

Code này em chạy không có vấn đề gì

PHP:
Function UniqueList(sArray)
    Dim SubArr, Item
    SubArr = sArray
    Set Dic = CreateObject("Scripting.Dictionary")
    For Each Item In SubArr
        If Item <> "" And Not Dic.Exists(Item) Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()
    Dim Tmp()
    Tmp = UniqueList(Sheet1.Range("A1:B50000"))
    ReDim Arr(1 To UBound(Tmp, 1) + 1, 1 To 1)
    For i = 0 To UBound(Tmp, 1)
        Arr(i + 1, 1) = Tmp(i)
    Next
    Sheets("Sheet2").[A1].Resize(i) = Arr
End Sub

Nhưng em thử thay 2 dòng

PHP:
Dim SubArr
Arr(i + 1, 1) = Tmp(i)

bằng
PHP:
Dim SubArr()
Arr(i + 1, 1) = Tmp(i,1)
thì bị lỗi ngay

--------------
Vì em vẫn nghĩ: Tmp(i)=Tmp(i,1)
SubArr là mảng thì khi khai báo Dim SubArr() và Dim SubArr có gì khác nhau ah?
Tmp() lấy từ UniqueList() và UniqueList() lấy từ Dic.Keys, mà Dic.Keys là mãng 1 chiều nên mãng Tmp() là mãng 1 chiều vì vậy không thể dùng Tmp(i,1)
 
Upvote 0
Nhưng em thử thay 2 dòng
PHP:
Dim SubArr
Arr(i + 1, 1) = Tmp(i)
bằng
PHP:
Dim SubArr()
Arr(i + 1, 1) = Tmp(i,1)
thì bị lỗi ngay

--------------
Vì em vẫn nghĩ: Tmp(i)=Tmp(i,1)
SubArr là mảng thì khi khai báo Dim SubArr() và Dim SubArr có gì khác nhau ah?
Biến Tmp nếu ghi thành Tmp(i, 1) thì bạn đã ngầm xem nó là mảng 2 chiều rồi ---> Sai (như vietohoai đã phân tích)
Còn về biến SubArr, là do bạn làm mọi thứ quá vắn tắt... Nếu đi từng bước thế này thì sẽ không có chuyện gì xảy ra:
Mã:
Sub Loc()
  Dim tmp(), i As Long, sArray
  [COLOR=#ff0000]sArray = Sheet1.Range("A1:B50000")[/COLOR]
  [COLOR=#ff0000]tmp = UniqueList(sArray)[/COLOR]
  ReDim Arr(1 To UBound(tmp, 1) + 1, 1 To 1)
  For i = 0 To UBound(tmp, 1)
    Arr(i + 1, 1) = tmp(i)
  Next
  Sheet1.[F1].Resize(i) = Arr
End Sub
-------------
Nói thêm: Bạn luôn sơ suất trong phần khai báo biến (không khai báo đầy đủ) ---> Sau này chú ý thêm vấn đề này... vì không phải cứ thấy code chạy được là xem như ta đã thành công đâu
 
Upvote 0
Thưa thày em tưởng sArray nó là tham số của hàm UniqueList thì không nên khai báo cụ thể:

PHP:
sArray = Sheet1.Range("A1:B50000")

Mà nó sẽ được ngầm hiểu thông qua Tmp ở câu:
PHP:
Tmp = UniqueList(Sheet1.Range("A1:B50000"))

-----------
Xin thày giảng giải cho tại sao khi khai báo như của thày ở trên thì không bị lỗi khi thay Dim SubArr bằng Dim SubArr() .
 
Lần chỉnh sửa cuối:
Upvote 0
Thưa thày em tưởng sArray nó là tham số của hàm UniqueList thì không nên khai báo cụ thể:

PHP:
sArray = Sheet1.Range("A1:B50000")

Mà nó sẽ được ngầm hiểu thông qua Tmp ở câu:
PHP:
Tmp = UniqueList(Sheet1.Range("A1:B50000"))

-----------
Xin thày giảng giải cho tại sao khi khai báo như của thày ở trên thì không bị lỗi khi thay Dim SubArr bằng Dim SubArr() .
Range và Array tuy có thể chuyển đổi qua lại nhưng trong 1 vài trường hợp cụ thế nó có phân biệt... Vậy ta nên tự mình chuyển đổi, đừng bắt code phải "ngầm hiểu" như bạn nói
Giống như bài toán đố vui tại đây:
http://www.giaiphapexcel.com/forum/showthread.php?7146-Đố-vui-về-VBA!&p=232941#post232941
Nếu ta không chuyển trước (bằng phép biến đổi Temp = SrcArray) thì code sẽ chạy sai
-------------
Nói tóm lại: Nếu "cải tiến" không như ý thì hãy trở về với các bước cơ bản
Sau này trong các bài toán lớn, bạn sẽ còn gặp những vụ tương tự rất thường xuyên mà nếu không làm đúng thứ tự sẽ lỗi tùm lum các nơi đến mức không còn biết đường nào mà lần...
 
Upvote 0
Mình xin nói thêm chổ này
Dim SubArr()

Tmp = UniqueList(Sheet1.Range("A1:B50000"))
Nếu bạn vẫn muốn giữ nguyên chúng, không muốn thêm biến sArray thì hãy sửa đoán gán biến Tmp thành:
Tmp = UniqueList(Sheet1.Range("A1:B50000").Value)
(tức là đằng nào cũng phải chuyển Range thành Array)
 
Upvote 0
Giúp em bài toán về lọc duy nhất, sau đó nối các phần tử duy nhất đó

Em xin gửi file đính kèm 9 (đầu vào của em cột A, kết quả minh họa tại ô D1)

Em làm như sau không được

PHP:
Function Connection(FindRng As Range)
    Dim i As Long, j As Long, Arr(), Tmp, Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    For i = 1 To FindRng.Rows.Count
        If FindRng.Value <> "" Then
            Tmp = FindRng
            If Not Dic.Exists(Tmp) Then
                j = j + 1
                Dic.Add Tmp, j
            End If
        End If
        ReDim Preserve Arr(1 To j)
        Arr(Dic.Item(Tmp)) = Tmp
    Next
    Connection = Join(Arr, ",")
End Function

Rất mong mọi ngưởi chỉ cho em chỗ sai để em khắc phục
----------
em chưa rõ lắm về cách dùng của Preserve, xin được chỉ bảo.
 

File đính kèm

  • Tap ham Jonit.xls
    16 KB · Đọc: 36
Lần chỉnh sửa cuối:
Upvote 0
Em xin gửi file đính kèm 9 (đầu vào của em cột A, kết quả minh họa tại ô D1)

Em làm như sau không được

PHP:
Function Connection(FindRng As Range)
    Dim i As Long, j As Long, Arr(), Tmp, Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    For i = 1 To FindRng.Rows.Count
        If FindRng.Value <> "" Then
            Tmp = FindRng
            If Not Dic.Exists(Tmp) Then
                j = j + 1
                Dic.Add Tmp, j
            End If
        End If
        ReDim Preserve Arr(1 To j)
        Arr(Dic.Item(Tmp)) = Tmp
    Next
    Connection = Join(Arr, ",")
End Function

Rất mong mọi ngưởi chỉ cho em chỗ sai để em khắc phục
----------
em chưa rõ lắm về cách dùng của Preserve, xin được chỉ bảo.
Sai cả rổ luôn!
Vầy mới đúng nè:
PHP:
Function Connection(byVal FindRng As Range) As String
  Dim tmp As String, Dic, sArray, Item
  sArray = FindRng.Value
  Set Dic = CreateObject("Scripting.Dictionary")
  For Each Item In sArray
    If Trim(CStr(Item)) <> "" Then
      tmp = Trim(CStr(Item))
      If Not Dic.Exists(tmp) Then Dic.Add tmp, ""
    End If
  Next
  If Dic.Count Then Connection = Join(Dic.Keys, ",")
End Function
 
Upvote 0
Em biết chỗ nhầm FindRng nó là một mảng chứ không phải 1 ô nên nếu dùng

PHP:
If FindRng.Value <> "" Then
là sai
Code của thày quá chuẩn rồi, ở đây em thử làm theo hướng khác xem bởi em đang tìm hiểu về Preserve, em sửa thành thế này cũng được thày ah

PHP:
Function Connection(FindRng As Range)
    Dim i As Long, j As Long, Arr(), Tmp, Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    For i = 1 To FindRng.Rows.Count
        If FindRng(i, 1) <> "" Then
            Tmp = FindRng(i, 1)
            If Not Dic.Exists(Tmp) Then
                j = j + 1
                Dic.Add Tmp, j
            End If
        End If
        ReDim Preserve Arr(1 To j)
        Arr(Dic.Item(Tmp)) = Tmp
    Next
    Connection = Join(Arr, ",")
End Function

-----------
Em đọc các tài liệu mà chưa tìm được khi nào người ta dùng Preserve, ở trên em bắt chước máy móc nhưng không hiểu lắm, xin thày chỉ cho
 
Lần chỉnh sửa cuối:
Upvote 0
Giả sử em nối tất cả các ô bằng dấu phảy (,), những ô trùng lặp đều được cả tức không tính yếu tố duy nhất.

Em viết thế này chắc chắn là sai, nhưng em chưa hiểu lắm tại sao nó sai, xin thày và mọi người chỉ dạy

PHP:
Function Connection(ByVal FindRng As Range) As String
  Dim sArray
  sArray = FindRng.Value
  Connection = Join(sArray, ",")
End Function
 
Upvote 0
Em đọc các tài liệu mà chưa tìm được khi nào người ta dùng Preserve, ở trên em bắt chước máy móc nhưng không hiểu lắm, xin thày chỉ cho
Nếu dùng mảng thì buộc khải khai báo số chiều + số phần tử trong mảng trước
- Trường hợp bạn biết trước số phần tử trong mảng thì chỉ cần ReDim Arr(số phần tử) là đủ
- Trường hợp bạn không biết trước số phần tử thì dùng ReDim Preserve... nghĩa là làm đến đâu, mở rổng mảng đến nấy
(đương nhiên đang nói trên cơ sở mảng 1 chiều, với mảng 2 chiều hoặc nhiều chiều thì có khác hơn 1 chút ---> Chỉ mở rộng được chiều cuối cùng khi dùng ReDim Preserve)
------------------
Giả sử em nối tất cả các ô bằng dấu phảy (,), những ô trùng lặp đều được cả tức không tính yếu tố duy nhất.

Em viết thế này chắc chắn là sai, nhưng em chưa hiểu lắm tại sao nó sai, xin thày và mọi người chỉ dạy

PHP:
Function Connection(ByVal FindRng As Range) As String
  Dim sArray
  sArray = FindRng.Value
  Connection = Join(sArray, ",")
End Function
Đương nhiên không được rồi (thí nghiệm sẽ biết liền) vì hàm Join chỉ làm việc với mảng 1 chiều mà thôi... Với Range, cho dù đã chuyển thành mảng rồi thì nó vẫn không phải mảng 1 chiều (nó luôn là mảng 2 chiều) nên dùng Join sẽ báo lỗi
Vậy, trước khi dùng Join, hãy For... Next để chuyển các phần tử trong Range vào mảng 1 chiều cái đã
 
Lần chỉnh sửa cuối:
Upvote 0
Tức là Preserve thì ban đầu khai thiếu số phần tử cũng không sao, sau khi tính toán nó tự động thêm phần tử cho mình hả thày.

---

Nếu vậy bài nào mình cũng cho tên này vào (ReDim Preserve) cho chắc ăn thì có vấn đề gì không ah?
 
Upvote 0
Tức là Preserve thì ban đầu khai thiếu số phần tử cũng không sao, sau khi tính toán nó tự động thêm phần tử cho mình hả thày.
Đúng vậy!
Nếu vậy bài nào mình cũng cho tên này vào (ReDim Preserve) cho chắc ăn thì có vấn đề gì không ah?
Tùy theo trường hợp bạn ơi... Nó còn liên quan đến tốc độ nữa đấy
Nói chung: Dùng cái gì cũng được, quan trọng là thích hợp, đúng lúc, đúng chổ ---> Đó mới là GIẢI QUYẾT HIỆU QUẢ
 
Upvote 0
Thầy Ndu ơi, Thầy coi làm giúp em bài này nhe Thầy!
 

File đính kèm

  • Book1.xls
    35 KB · Đọc: 22
Upvote 0
Thầy Ndu ơi, Thầy coi làm giúp em bài này nhe Thầy!
Bài của bạn thuộc dạng trích lọc, hơn nữa nó lại có liên quan đến kế toán
Vậy bạn phải cho vào box liên quan đến trích lọc hoặc kế toán chứ, sao lại cho vào topic này?
Quăng bài tùm lum sẽ bị xóa đấy nhé!
 
Upvote 0
Xin lỗi Thầy vì em nôn quá nên đưa bài ra 2 topic, mong Thầy và DĐ tha lỗi, em sẽ đưa qua box trích lọc.
 
Upvote 0
Em có dữ liệu từ A1:A10 sheet 1 là dạng text (kiểu số) ví dụ
201202
201203
..........

Em đang thử dùng mảng để tìm ra ô là nào là số nhưng chưa được
Anh chị sửa code giúp em với

PHP:
Sub test()
Dim sArr()
    sArr = Sheet1.Range("A1:A10").Value
    For i = 1 To UBound(sArr, 1)
        If sArr(i, 1) <> "" Then
           If IsNumeric(sArr(i, 1)) Then
              MsgBox "Sheet1 dong thu" & i & " format la so "
              Exit Sub
           End If
        End If
    Next i
  
End Sub
 

File đính kèm

  • Arr check if numeric-test.xls
    27.5 KB · Đọc: 19
Upvote 0
Em có dữ liệu từ A1:A10 sheet 1 là dạng text (kiểu số) ví dụ
201202
201203
..........

Em đang thử dùng mảng để tìm ra ô là nào là số nhưng chưa được
Anh chị sửa code giúp em với

PHP:
Sub test()
Dim sArr()
    sArr = Sheet1.Range("A1:A10").Value
    For i = 1 To UBound(sArr, 1)
        If sArr(i, 1) <> "" Then
           If IsNumeric(sArr(i, 1)) Then
              MsgBox "Sheet1 dong thu" & i & " format la so "
              Exit Sub
           End If
        End If
    Next i
  
End Sub
Thay IsNumeric bằng WorksheetFunction.IsNumber thử xem
 
Upvote 0
Thay IsNumeric bằng WorksheetFunction.IsNumber thử xem

Ẹc, được Anh NDU ạh.
EM nhớ có lần anh dặn, không nên dùng công thức excel trong VBA. Việc này sẽ làm chậm file

Em đã test thử với hơn 10.000 dòng. thấy ok anh ạh

Cám ơn Anh nhé
Qua ví dụ này chứng tở isnumeric không chơi với mảng
 
Upvote 0
Web KT

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

Back
Top Bottom