Thủ thuật tạo một Array từ một Range (1 người xem)

Liên hệ QC

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

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,662
Được thích
16,725
Giới tính
Nam
Bài này tôi muốn truyền đạt một kinh nghiệm đối với một số thành viên đang tập tành với mảng lấy dữ liệu từ một vùng trong sheet.


1)
Trước tiên chúng ta phải khẳng định với nhau rằng, tạo một mảng (array) từ một vùng (range) trên sheet, thì mảng đó luôn luôn là mảng 2 chiều và có biên dưới (Lbound) bắt đầu từ 1 ở cả 2 chiều.


2)
Kế tiếp, phải khẳng định rằng, để trở thành một mảng từ 1 vùng, thì vùng đó phải có tối thiểu từ 2 ô (cell) trở lên. Với mảng chỉ có 1 ô thì đó không phải là một mảng.

Arr = Range("B1:B2") ---> Arr là một array

Arr = Range("B1") ----> Arr không phải là một array


3)
Không phải lúc nào ta cũng có sẳn một vùng cố định để mảng nhận giá trị như:

Arr = Range("B1:B100")

Một cơ sở dữ liệu (CSDL) không bao giờ có chuyện cố định hàng cuối là 100 hay 1000 hay là một số cụ thể nào, vì thế, VBA cung cấp cho chúng ta một thuộc tính của Range đó là End (Range.End Property).

Các đối số của End là: xlDown, xlToLeft, xlToRight, xlUp

Với End ta có thể hiểu nôm na như chúng ta dùng phím Ctrl kết hợp với một phím mũi tên (lên, xuống, trái phải) để chúng ta di chuyển nhanh đến một ô cuối cùng có giá trị ở trên, ở dưới, ở bên trái, ở bên phải.

Thông thường, để xác định hàng (row) cuối cùng có giá trị của một CSDL thì ta thường dùng Range().End(xlUp) hoặc Range().End(xlDown).

Với Range().End(xlUp) thì Range phải xuất phát từ dưới lên, ngược lại, Range().End(xlDown) Range xuất phát từ trên xuống.

Ví dụ dưới đây để lấy hàng cuối cùng của một cột có giá trị:

Dim LastRow As Long

LastRow = Range("B65536").End(xlUp).Row

hoặc:

LastRow = Range("B1").End(xlDown).Row

Vậy khi nào ta dùng xlUp và khi nào dùng xlDown?

Trong một CSDL chuẩn thường thì chúng có các hàng liền kề nhau, và không có những dòng trống ở cột đầu tiên nên chúng ta có thể chọn phương án xlDown là hợp lý. Tuy nhiên khác với Access (một CSDL không chấp nhận có dòng trống), thì Excel đôi khi có một số hàng bị chúng ta xóa (Clear) đi thay vì phải Delete nên nếu dùng xlDown thì có thể chúng ta không thể lấy hết hàng cuối cùng.


4)
Nếu dùng xlUp thì ta nên lấy số hàng lớn nhất nào? 65536 hay 1048576?

Nếu như Excel 2003 trở về trước, có số hàng lớn nhất là 65536, thì Excel 2007 trở về sau có số hàng lớn nhất là 1048576. Để code ta viết "thà giết lầm còn hơn bỏ sót" thì ta chẳng cần quan tâm đến các con số này, thay vào đó ta sẽ dùng Rows.Count để nó xác định số hàng lớn nhất của một file Excel mà không cần quan tâm đến phiên bản nào cả!

LastRow = Range("B" & Rows.Count).End(xlUp).Row


5)
Cách bẫy lỗi để có được một mảng từ việc dùng End:

Tại sao chúng ta phải bẫy lỗi? Và lỗi thường xuất phát từ đâu?

Như đã nói ở mục 2, mảng lấy giá trị từ một range luôn luôn phải có tối thiểu từ 2 ô trở lên, nếu không chúng sẽ bị lỗi:

Mã:
Sub Test1()
    Dim Arr()
    Dim LastRow As Long
    LastRow = Range("B" & Rows.Count).End(xlUp).Row
    Arr = Range("B1:B" & LastRow)
End Sub

Với thủ tục trên nếu LastRow = 1 thì chắc chắn thủ tục trên sẽ báo lỗi Type mismatch.

Với mảng từ 2 cột trở lên thì ta sẽ không bao giờ bị lỗi này:

Arr = Range("B1:D" & LastRow)

Nhưng chúng ta cũng phải bẫy lỗi cho dữ liệu, vì sao?

Thường thì một CSDL sẽ có tiêu đề cột, khi ta muốn lấy dữ liệu từ CSDL này để gán cho một mảng thì ta phải loại trừ tiêu đề này ra, và ta cũng phải ngăn chặn việc dữ liệu chưa được nhập vào đó hàng nào, vì thế ta phải đặt điều kiện cho nó:

Giả sử hàng 1 là hàng tiêu đề, từ hàng 2 trở đi là dữ liệu thì ta phải bẫy lỗi như sau:

Mã:
Sub Test2()
    Dim Arr()
    Dim LastRow As Long
    LastRow = Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        Arr = Range("B2:[COLOR=#ff0000]D[/COLOR]" & LastRow)
    End If
End Sub


Code trên là dùng cho mảng nhiều cột, nhưng với mảng 1 cột thì phải bẫy lỗi khác hơn:

Mã:
Sub Test3()
    Dim Arr()
    Dim LastRow As Long
    LastRow = Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        If LastRow = 2 Then
            Dim ArrTmp(1 To 1, 1 To 1)
            ArrTmp(1, 1) = Range("B2")
            Arr = ArrTmp
        Else
            Arr = Range("B2:B" & LastRow)
        End If
    End If
End Sub

Vì sao ta phải làm như thế? Bởi vì để Arr là một mảng thì ít nhất Arr phải bằng Range("B2:B3") chứ không thể bằng Range("B2") được.

Nhưng chúng ta có thể lo xa hơn, nếu dữ liệu đã đạt tới hàng cuối cùng của sheet thì chúng ta không thể dùng xlUp được nữa đấy nhé! Tuy nhiên ta có thể không ngại vì theo tôi, chúng ta nên chừa dòng cuối cùng trong CSDL.

Với xlDown cũng phải bẩy lỗi, nếu dữ liệu chưa được nhập gì cả thì khả năng nó nhận hàng cuối cùng cũng là hàng cuối cùng lớn nhất, cho nên tùy theo "hoàn cảnh" mà ta bẫy lỗi như thế nào để phù hợp.


6) Luôn luôn đi kèm Range là TÊN SHEET:

Nếu ta không đưa tên sheet vào vùng gán vào mảng thì đương nhiên máy sẽ ngầm hiểu là sheet hiện hành (ActiveSheet), vì thế để xác định là sheet nào cần gán vào mảng thì ta phải ghi rõ tên sheet vào vùng đó.

Tên sheet có thể là Sheet Name và cũng có thể là Sheet CodeName.

Sheet Name là tên sheet mà ta có thể thấy trên sheet tab và CodeName là tên mà ta có thể thấy trong VBA.

Nếu như một sheet có SheetName là "TenSheet" và CodeName là "Sheet1" thì thủ tục phải như sau:

Mã:
Sub Test4()
    Dim Arr()
    Dim LastRow As Long
    LastRow = [COLOR=#ff0000]Sheet1[/COLOR].Range("B" & Rows.Count).End(xlUp).Row
    'hoac:
    LastRow = [COLOR=#0000ff]Sheets("TenSheet")[/COLOR].Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        Arr = [COLOR=#ff0000]Sheet1[/COLOR].Range("B2:D" & LastRow)
        'hoac:
        Arr = [COLOR=#0000ff]Sheets("TenSheet")[/COLOR].Range("B2:D" & LastRow)
    End If
End Sub


7) Lưu ý đến việc AutoFilter:

Nếu một CSDL đang ở chế độ Filter thì việc xác định hàng sẽ gặp một "sự cố" mất dữ liệu, những giá trị không bị ẩn ở vùng dữ liệu khi Filter sẽ được cập nhật còn lại sẽ bị mất, vì thế chúng ta phải kiểm tra chế độ này trước khi thực hiện việc gán mảng:

Mã:
Sub Test5()
    Dim Arr()
    Dim LastRow As Long
[COLOR=#ff0000]    If Sheet1.AutoFilterMode Then[/COLOR]
[COLOR=#ff0000]        Sheet1.AutoFilterMode = False[/COLOR]
[COLOR=#ff0000]    End If[/COLOR]
    LastRow = Sheet1.Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        Arr = Sheet1.Range("B2:D" & LastRow)
    End If
End Sub

Nhưng nếu dữ liệu không có AutoFilter mà dữ liệu chỉ bị Hide thì dù hàng có bị ẩn hay không cũng không bị mất dữ liệu khi gán lên mảng đâu, cho nên chúng ta cũng không cần phải lo về vấn đề này.


Đó là những kinh nghiệm của tôi về xác định một vùng để gán vào một mảng, có thể có những bổ sung từ những thành viên khác, hy vọng bài này sẽ phần nào giúp ích cho các bạn khi mới học về mảng để vận dụng cho bài tập của mình.
 
Lần chỉnh sửa cuối:
6) Luôn luôn đi kèm Range là TÊN SHEET.

Nếu ta không đưa tên sheet vào vùng gán vào mảng thì đương nhiên máy sẽ ngầm hiểu là ActiveSheet vì thế để xác định là sheet nào cần gán vào mảng thì ta phải ghi rõ tên sheet vào vùng đó.

Tên sheet có thể là Sheet Name và cũng có thể là Sheet CodeName.

Sheet Name là tên sheet mà ta có thể thấy trên sheet tab và CodeName là tên mà ta có thể thấy trong VBA.

Nếu như một sheet có SheetName là "TenSheet" và CodeName là "Sheet1" thì thủ tục phải như sau:

Mã:
Sub Test4()
    Dim Arr()
    Dim LastRow As Long
    LastRow = [COLOR=#ff0000]Sheet1[/COLOR].Range("B" & [B][COLOR=#ffa500]Rows[/COLOR][/B].Count).End(xlUp).Row
    'hoac:
    LastRow = [COLOR=#0000ff]Sheets("TenSheet")[/COLOR].Range("B" & [B][COLOR=#ffa500]Rows[/COLOR][/B].Count).End(xlUp).Row
    If LastRow > 1 Then
        Arr = [COLOR=#ff0000]Sheet1[/COLOR].Range("B2:D" & LastRow)
        'hoac:
        Arr = [COLOR=#0000ff]Sheets("TenSheet")[/COLOR].Range("B2:D" & LastRow)
    End If
End Sub

Mấy chỗ màu vàng mà không có tên sheet thì cũng bằng thừa
--------------
Từ ngày dùng mảng, ít khi nào tôi dùng tới mấy cái End(....) gì gì đó cho mệt. Lý do:
- Mất công bẫy lỗi
- Tốc độ cũng chẳng cải thiện bao nhiêu so với việc tôi chọn dư ra 1 chút
- Mấy thằng End(...) này đụng phải Filter thì coi như tiêu đời
 
Lần chỉnh sửa cuối:
Upvote 0
Mấy chỗ màu vàng mà không có tên sheet thì cũng bằng thừa
Chỗ màu vàng không có tên sheet là hợp lý, bởi một file mở ra luôn luôn có một ActiveSheet, không bao giờ có chuyện tất cả các sheet đều bị Hide. Vì vậy Rows.Count ở đây được hiểu là ActiveSheet.Rows.Count; thủ tục này chỉ cần lấy số hàng cuối cùng của một sheet vì thế không nhất thiết nó phải có địa chỉ của bất kỳ sheet nào.
 
Upvote 0
Từ ngày dùng mảng, ít khi nào tôi dùng tới mấy cái End(....) gì gì đó cho mệt. Lý do:
- Mất công bẫy lỗi
- Tốc độ cũng chẳng cải thiện bao nhiêu so với việc tôi chọn dư ra 1 chút
- Mấy thằng End(...) này đụng phải Filter thì coi như tiêu đời

Đúng thế, phần này em cũng định bổ sung vào bài này! Nếu không có nó có thể ta không nhận hết các hàng khi đang bị Filter:

Mã:
Sub Test5()
    Dim Arr()
    Dim LastRow As Long
[COLOR=#ff0000]    If Sheet1.AutoFilterMode Then[/COLOR]
[COLOR=#ff0000]        Sheet1.AutoFilterMode = False[/COLOR]
[COLOR=#ff0000]    End If[/COLOR]
    LastRow = Sheet1.Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        Arr = Sheet1.Range("B2:D" & LastRow)
    End If
End Sub
 
Upvote 0
Chỗ màu vàng không có tên sheet là hợp lý, bởi một file mở ra luôn luôn có một ActiveSheet, không bao giờ có chuyện tất cả các sheet đều bị Hide. Vì vậy Rows.Count ở đây được hiểu là ActiveSheet.Rows.Count; thủ tục này chỉ cần lấy số hàng cuối cùng của một sheet vì thế không nhất thiết nó phải có địa chỉ của bất kỳ sheet nào.

Thì chính vì Rows.Count được hiểu là ActiveSheet.Rows.Count nên Nghĩa không thể dùng nó để làm việc với Sheet khác được. Đang đứng tại sheet 2 mà dùng code trên thì coi như.. hết phim
Còn nếu Nghĩa muốn làm việc tại ActiveSheet thì việc đưa tên sheet vào code trên cũng thừa luôn
Tóm lại:
- Nếu ta muốn code hoạt động ở bất kỳ sheet nào thì BẮT BUỘC phải ghi tên sheet đằng trước tất cả các tham chiếu
- Nếu ta chỉ muốn code chạy trên sheet hiện hành thì không cần ghi tên sheet ở bất kỳ tham chiếu nào
 
Upvote 0
Nếu mới chỉ có 1 ô có giá trị mà dùng .End cũng bị lỗi đó Nghĩa.
 
Upvote 0
Thì chính vì Rows.Count được hiểu là ActiveSheet.Rows.Count nên Nghĩa không thể dùng nó để làm việc với Sheet khác được. Đang đứng tại sheet 2 mà dùng code trên thì coi như.. hết phim
Còn nếu Nghĩa muốn làm việc tại ActiveSheet thì việc đưa tên sheet vào code trên cũng thừa luôn
Tóm lại:
- Nếu ta muốn code hoạt động ở bất kỳ sheet nào thì BẮT BUỘC phải ghi tên sheet đằng trước tất cả các tham chiếu
- Nếu ta chỉ muốn code chạy trên sheet hiện hành thì không cần ghi tên sheet ở bất kỳ tham chiếu nào
Em chỉ cần nó xác định hàng cuối cùng của một phiên bản Excel là bao nhiêu: 65536 hay 1048576 mà thôi, thì đâu cần nó ở sheet nào đâu?
 
Upvote 0
Nếu mới chỉ có 1 ô có giá trị mà dùng .End cũng bị lỗi đó Nghĩa.
Vâng, em cũng đã trình bày ở phần 5 này rồi mà Anh?


5)
Cách bẫy lỗi để có được một mảng từ việc dùng End:

Tại sao chúng ta phải bẫy lỗi? Và lỗi thường xuất phát từ đâu?

Như đã nói ở mục 2, mảng lấy giá trị từ một range luôn luôn phải có tối thiểu từ 2 ô trở lên, nếu không chúng sẽ bị lỗi:

Mã:
Sub Test1()
    Dim Arr()
    Dim LastRow As Long
    LastRow = Range("B" & Rows.Count).End(xlUp).Row
    Arr = Range("B1:B" & LastRow)
End Sub

Với thủ tục trên nếu LastRow = 1 thì chắc chắn thủ tục trên sẽ báo lỗi Type mismatch.

Với mảng từ 2 cột trở lên thì ta sẽ không bao giờ bị lỗi này:

Arr = Range("B1:D" & LastRow)

Nhưng chúng ta cũng phải bẫy lỗi cho dữ liệu, vì sao?

Thường thì một CSDL sẽ có tiêu đề cột, khi ta muốn lấy dữ liệu từ CSDL này để gán cho một mảng thì ta phải loại trừ tiêu đề này ra, và ta cũng phải ngăn chặn việc dữ chưa được nhập vào đó hàng nào, vì thế ta phải đặt điều kiện cho nó:

Giả sử hàng 1 là hàng tiêu đề, từ hàng 2 trở đi là dữ liệu thì ta phải bẫy lỗi như sau:

Mã:
Sub Test2()
    Dim Arr()
    Dim LastRow As Long
    LastRow = Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        Arr = Range("B2:[COLOR=#ff0000]D[/COLOR]" & LastRow)
    End If
End Sub


Code trên là dùng cho mảng nhiều cột, nhưng với mảng 1 cột thì phải bẫy lỗi khác hơn:

Mã:
Sub Test3()
    Dim Arr()
    Dim LastRow As Long
    LastRow = Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        If LastRow = 2 Then
            Dim ArrTmp(1 To 1, 1 To 1)
            ArrTmp(1, 1) = Range("B2")
            Arr = ArrTmp
        Else
            Arr = Range("B2:B" & LastRow)
        End If
    End If
End Sub

Vì sao ta phải làm như thế? Bởi vì để Arr là một mảng thì ít nhất Arr phải bằng Range("B2:B3") chứ không thể bằng Range("B2") được.
 
Upvote 0
Đúng thế, phần này em cũng định bổ sung vào bài này!

Có nghĩa là Nghĩa sẽ còn viết tiếp mấy bài nữa, đúng không?
Vậy để khỏi làm loãng đề tài, tôi xóa hết những bài hỏi đáp nãy giờ và sau khi Nghĩa hoàn tất topic, nếu có bàn luận sẽ tính sau. Đồng ý chứ?
(đồng ý thì tự xóa luôn hen)
 
Upvote 0
Có nghĩa là Nghĩa sẽ còn viết tiếp mấy bài nữa, đúng không?
Vậy để khỏi làm loãng đề tài, tôi xóa hết những bài hỏi đáp nãy giờ và sau khi Nghĩa hoàn tất topic, nếu có bàn luận sẽ tính sau. Đồng ý chứ?
(đồng ý thì tự xóa luôn hen)
Không ạ, bài này càng có nhiều thảo luận thì càng có nhiều kinh nghiệm hơn ạ vì thế em nghĩ là ai cũng có thể hỏi và trả lời thì sẽ hay hơn, đôi khi em được học hỏi hoặc sáng tỏ nhiều vấn đề ạ. Bài đó nhờ Thầy gợi ý nên mới bổ sung sau thôi ạ.
 
Upvote 0
Mã:
Sub Test5()
    Dim Arr()
    Dim LastRow As Long
    If Sheet1.AutoFilterMode Then
        Sheet1.AutoFilterMode = False
    End If
    LastRow = Sheet1.Range("B" & Rows.Count).End(xlUp).Row
    If LastRow > 1 Then
        [COLOR=#ff0000]Arr = Sheet1.Range("B2:D" & LastRow)[/COLOR]
    End If
End Sub

Nếu muốn lấy công thức vào mảng thì dòng đỏ đỏ là: Arr = Sheet1.Range("B2:D" & LastRow).Formula (mặc định, nếu không ghi gì là Value)

----------------------------------------------------------------

Nên thêm chuỗi "và ngược lại ..." vào tiêu đề mới có nhiều chuyện để bàn hơn.
 
Upvote 0
@ xin chào anh chị,

nếu nếu số liệu của mình nằm trên một hàng
[A3:H3] chằng hạng
nếu khai báo là
Arr=[A3:H3].value
thì ubound(arr) chỉ là một
nhờ anh chị chỉ giúp với
cám ơn nhiều
 
Upvote 0
@ xin chào anh chị,

nếu nếu số liệu của mình nằm trên một hàng
[A3:H3] chằng hạng
nếu khai báo là
Arr=[A3:H3].value
thì ubound(arr) chỉ là một
nhờ anh chị chỉ giúp với
cám ơn nhiều
ubound(arr) tương đương với Ubound(arr,1) - kích thước chiều thứ nhất (dòng) mặc định khi không ghi gì.
 
Lần chỉnh sửa cuối:
Upvote 0
@ xin chào anh chị,

nếu nếu số liệu của mình nằm trên một hàng
[A3:H3] chằng hạng
nếu khai báo là
Arr=[A3:H3].value
thì ubound(arr) chỉ là một
nhờ anh chị chỉ giúp với
cám ơn nhiều

Ubound và Lbound là các hàm để tính biên trên, biên dưới của một mảng.

Như tôi đã nói, với mảng được tạo ra từ một range thì mảng đó luôn luôn là mảng 2 chiều và có biên dưới luôn bắt đầu từ 1 cho các chiều.

Ubound (biên trên) với mảng 2 chiều thì phải xác định rõ nó ở chiều nào.

Để xác định chiều "hàng": Ubound(Arr, 1) hoặc tắt: Ubound(Arr)

Để xác định chiều "cột": Ubound(Arr, 2)

Tôi nghĩ bạn đang cần xác định nó có bao nhiêu cột phải không? Còn với Ubound(Arr) thì nó xác định chỉ có 1 hàng và kết quả là 1 hoàn toàn đúng.
 
Upvote 0
Là như vậy
nếu tôi có 1 mảng như sau
arr=[A1:A10].value
tôi muốn duyệt qua các phân tử của nó thỉ
for i=1 to ubound(arr)

bây giờ mảng là
arr=[A1:H1].value
thì dùng vòng lặp như thế nào để duệt qua các phân tử

cám ơn
 
Upvote 0
Là như vậy
nếu tôi có 1 mảng như sau
arr=[A1:A10].value
tôi muốn duyệt qua các phân tử của nó thỉ
for i=1 to ubound(arr)

bây giờ mảng là
arr=[A1:H1].value
thì dùng vòng lặp như thế nào để duệt qua các phân tử

cám ơn
Tùy theo mảng "đầu vào" như thế nào để bạn có thể dùng vòng lặp duyệt cho hiệu quả.

Với chiều duyệt theo hàng:

Mã:
Sub Test6()

    Dim r As Long
    Dim Arr(), ArrOther()
    
    Arr = Range("A1:A10")
    
[COLOR=#0000cd]    ReDim [B]ArrOther[/B](1 To UBound(Arr, 1), 1 To 1)[/COLOR]
    
    For r = 1 To UBound(Arr, 1)
        ArrOther(r, 1) = [COLOR=#ff0000][B]Arr(r, 1)[/B][/COLOR]
    Next
    
End Sub

Với chiều duyệt theo cột:

Mã:
Sub Test7()

    Dim c As Long
    Dim Arr(), ArrOther()
    
    Arr = Range("A1:H1")
    
[COLOR=#0000cd]    ReDim ArrOther(1 To 1, 1 To UBound(Arr, 2))[/COLOR]
    
    For c = 1 To UBound(Arr, 2)
        ArrOther(1, c) = [COLOR=#ff0000]Arr(1, c)[/COLOR]
    Next
    
End Sub

Với cả 2 chiều hàng và cột:

Mã:
Sub Test8()

    Dim Arr(), ArrOther()
    Dim c As Long, r As Long
    Dim uc As Long, ur As Long
    
    Arr = Range("A1:H10")
    
[COLOR=#ff0000]    ur = UBound(Arr, 1)
    uc = UBound(Arr, 2)
[/COLOR]    
    ReDim ArrOther(1 To ur, 1 To uc)
    
    For c = 1 To uc
        For r = 1 To ur
            ArrOther(r, c) = Arr(r, c)
        Next
    Next
    
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
đã hiếu, cám ơn anh Nghĩa, vậy là để đưa nó vào mảng thì phải dùng vòng lặp để đưa các phân từ từ chiều ngang sang chiều dọc

như vậy nếu mình dùng hàm transpose như vậy có được ko anh?
Mã:
Sub ttt()

Dim Arr As Variant
Arr = Application.WorksheetFunction.Transpose([A1:H1])
    For i = 1 To UBound(Arr)
        MsgBox Arr(i, 1)
    Next
End Sub
 
Upvote 0
đã hiếu, cám ơn anh Nghĩa, vậy là để đưa nó vào mảng thì phải dùng vòng lặp để đưa các phân từ từ chiều ngang sang chiều dọc

như vậy nếu mình dùng hàm transpose như vậy có được ko anh?
Mã:
Sub ttt()

Dim Arr As Variant
[COLOR=#ff0000][/COLOR][B]Arr = [/B][COLOR=#ff0000][B]Application.WorksheetFunction.Transpose([/B][/COLOR][B][A1:H1][/B][COLOR=#ff0000][B])[/B][/COLOR]
    For i = 1 To UBound(Arr)
        MsgBox [SIZE=4][COLOR=#0000cd][B]Arr([/B][/COLOR][COLOR=#ff0000][B]i[/B][/COLOR][COLOR=#0000cd][B], 1)[/B][/COLOR][/SIZE]
    Next
End Sub
Trời ơi, thêm thằng màu đỏ làm chi trời! Khi đã xác định là duyệt theo CỘT thì ta cứ Ubound(Arr, 2) thôi.

Cứ việc:

Mã:
    Arr = [A1:H1]

    For i = 1 To UBound(Arr, [COLOR=#ff0000]2[/COLOR])
        MsgBox [SIZE=4][COLOR=#0000CD][B]Arr(1, [/B][/COLOR][COLOR=#ff0000][B]i[/B][/COLOR][COLOR=#0000CD][B])[/B][/COLOR][/SIZE]
    Next

Lưu ý vị trí chữ i nha.
 
Upvote 0
Trời ơi, thêm thằng màu đỏ làm chi trời! Khi đã xác định là duyệt theo CỘT thì ta cứ Ubound(Arr, 2) thôi.

Cứ việc:

Mã:
    Arr = [A1:H1]

    For i = 1 To UBound(Arr, [COLOR=#ff0000]2[/COLOR])
        MsgBox [SIZE=4][COLOR=#0000CD][B]Arr(1, [/B][/COLOR][COLOR=#ff0000][B]i[/B][/COLOR][COLOR=#0000CD][B])[/B][/COLOR][/SIZE]
    Next

Lưu ý vị trí chữ i nha.

vậy là mất công thầy giảng cà buôi mà ko hiểu gì hết rồi.............kakakak
ok, cám ơn thầy
 
Upvote 0
Trời ơi, thêm thằng màu đỏ làm chi trời! Khi đã xác định là duyệt theo CỘT thì ta cứ Ubound(Arr, 2) thôi.

Cứ việc:

Mã:
    Arr = [A1:H1]

    For i = 1 To UBound(Arr, [COLOR=#ff0000]2[/COLOR])
        MsgBox [SIZE=4][COLOR=#0000CD][B]Arr(1, [/B][/COLOR][COLOR=#ff0000][B]i[/B][/COLOR][COLOR=#0000CD][B])[/B][/COLOR][/SIZE]
    Next

Lưu ý vị trí chữ i nha.

Đề phòng có lỗi xảy ra trên cell, chẳng hạn [A1] có công thức nhưng đang bị #N/A
 
Upvote 0
Dùng mảng 1 chiều để nhận giá trị từ một CSDL

Với bài viết này, tôi sẽ giới thiệu cho các bạn sử dụng mảng 1 chiều để chứa các mảng 2 chiều 1 cột thay vì chỉ đơn thuần là mảng 2 chiều chứa tất cả các cột.

Với một CSDL với 20 cột và 65.534 dòng, tôi đã thử nghiệm như sau:

1) Dùng mảng 2 chiều để nhận toàn bộ giá trị của CSDL:

Mã:
Sub Test9()
    Dim T As Double
    T = Timer
    Dim Arr()
[COLOR=#ff0000][B]    Arr = Sheet1.Range("A2:T65535")[/B][/COLOR]
    MsgBox Timer - T
End Sub

2) Dùng mảng 1 chiều để chia nhỏ CSDL thành 20 cột:

Mã:
Sub Test10()
    Dim T As Double
    T = Timer
[COLOR=#0000ff][B]    Dim Arr(0 To 19)[/B][/COLOR]
    Dim c As Byte
    With Sheet1.Range("A2:A65535")
[B][COLOR=#0000ff]        For c = 0 To 19[/COLOR][/B]
[B][COLOR=#0000ff]            Arr(c) = .Offset(, c)[/COLOR][/B]
[B][COLOR=#0000ff]        Next[/COLOR][/B]
    End With
    MsgBox Timer - T
End Sub

Kết quả thực hiện, mảng 1 chiều cho thời gian nhanh gấp đôi mảng 2 chiều! Với mảng 1 chiều chúng ta còn linh hoạt hơn khi đảo cột ở các vị trí khác nhau để dễ dàng tạo một nguồn dữ liệu mới để vòng lặp thực hiện nhanh chóng, nhất là trong các vấn đề lọc dữ liệu.

Một lưu ý là nếu các bạn dùng thuộc tính Range.End thì các bạn phải nhớ rằng mảng 1 cột phải có 2 cells trở lên mới thành 1 mảng các bạn nhé!
 

File đính kèm

Upvote 0
2) Dùng mảng 1 chiều để chia nhỏ CSDL thành 20 cột:

Kết quả thực hiện, mảng 1 chiều cho thời gian nhanh gấp đôi mảng 2 chiều! Với mảng 1 chiều chúng ta còn linh hoạt hơn khi đảo cột ở các vị trí khác nhau để dễ dàng tạo một nguồn dữ liệu mới để vòng lặp thực hiện nhanh chóng, nhất là trong các vấn đề lọc dữ liệu.
Cần nói rõ là đây là mảng trong mảng: Mảng 1 chiều gồm 20 phần tử, mỗi phần tử là 1 mảng 2 chiều. Truy xuất, xét điều kiện, và tính toán đối với mảng trong mảng vẫn chưa phải là tối ưu.
 
Lần chỉnh sửa cuối:
Upvote 0
Cần nói rõ là đây là mảng trong mảng: Mảng 1 chiều gồm 20 phần tử, mỗi phần tử là 1 mảng 2 chiều. Truy xuất, xét điều kiện, và tính toán đối với mảng trong mảng vẫn chưa phải là tối ưu.
Sư phụ nói vậy thì có dẫn chứng phải không ạ?
 
Upvote 0
Dẫn chứng:
1. Chính Nghĩa nói mấy lần
2. Trong topic [THI] 65000 dòng, bài nào mảng trong mảng thì chậm hơn.
Chậm hay không chậm thì do yêu tố add giữa Dictionary và Collection, còn mảng trong mảng không hề chậm! Bằng chứng rõ ràng là dùng vòng lặp và chuyển thành mảng trong mảng ở mảng 1 chiều thì tốc độ đã tăng gấp đôi việc gán bằng mảng 2 chiều cho cả CSDL. Rất nhanh chứ không chậm.
 
Lần chỉnh sửa cuối:
Upvote 0
Chậm hay không chậm thì do yêu tố add giữa Dictionary và Collection, còn mảng trong mảng không hề chậm! Bằng chứng rõ ràng là dùng vòng lặp và chuyển thành mảng trong mảng ở mảng 1 chiều thì tốc độ đã tăng gấp đôi việc gán bằng mảng 2 chiều cho cả CSDL. Rất nhanh chứ không chậm.

Tôi không hề phản đối việc "dùng vòng lặp và chuyển thành mảng trong mảng ở mảng 1 chiều không hề chậm", test10 nhanh gần gấp đôi test9. (vẫn là không đọc kỹ, ngộ nhỉ?)

Tôi chỉ nói rằng sau khi tạo rồi thì truy xuất, xét điều kiện, tính toán "chưa tối ưu".
Trong topic [THI], làm theo vodoi2x: Không tạo mảng 20 cột mà tạo riêng 5 mảng 1 cột (hoặc 20 nếu cần). Đó mới là tối ưu.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi không hề phản đối việc "dùng vòng lặp và chuyển thành mảng trong mảng ở mảng 1 chiều không hề chậm", test10 nhanh gần gấp đôi test9. (vẫn là không đọc kỹ, ngộ nhỉ?)

Tôi chỉ nói rằng sau khi tạo rồi thì truy xuất, xét điều kiện, tính toán "chưa tối ưu".
Trong topic [THI], làm theo vodoi2x: Không tạo mảng 20 cột mà tạo riêng 5 mảng 1 cột (hoặc 20 nếu cần). Đó mới là tối ưu.
Vậy thì đo tốc độ 20 mảng 2 chiều và 1 mảng với 20 phần tử trên bài đó xem sao!
 
Upvote 0
Bổ sung:
1. Nạp mảng rồi còn phải xử lý mảng, chính việc truy xuất và xử lý mới quan trọng.
2. Việc so sánh mảng trong mảng và mảng đơn không liên quan đến việc so sánh Dic và Collection, cứ dùng 1 cái thôi, và so sánh.
 
Upvote 0
Lấy file của bài 23 và thử với thủ tục này:

Mã:
Sub Test11()
    Dim T As Double
    T = Timer
    Dim Cot1(), Cot2(), Cot3(), Cot4(), Cot5(), Cot6(), Cot7(), Cot8(), Cot9(), Cot10()
    Dim Cot11(), Cot12(), Cot13(), Cot14(), Cot15(), Cot16(), Cot17(), Cot18(), Cot19(), Cot20()
    Cot1 = Sheet1.Range("A2:A65535")
    Cot2 = Sheet1.Range("B2:B65535")
    Cot3 = Sheet1.Range("C2:C65535")
    Cot4 = Sheet1.Range("D2:D65535")
    Cot5 = Sheet1.Range("E2:E65535")
    Cot6 = Sheet1.Range("F2:F65535")
    Cot7 = Sheet1.Range("G2:G65535")
    Cot8 = Sheet1.Range("H2:H65535")
    Cot9 = Sheet1.Range("I2:I65535")
    Cot10 = Sheet1.Range("J2:J65535")
    Cot11 = Sheet1.Range("K2:K65535")
    Cot12 = Sheet1.Range("L2:L65535")
    Cot13 = Sheet1.Range("M2:M65535")
    Cot14 = Sheet1.Range("N2:N65535")
    Cot15 = Sheet1.Range("O2:O65535")
    Cot16 = Sheet1.Range("P2:P65535")
    Cot17 = Sheet1.Range("Q2:Q65535")
    Cot18 = Sheet1.Range("R2:R65535")
    Cot19 = Sheet1.Range("S2:S65535")
    Cot20 = Sheet1.Range("T2:T65535")
    MsgBox Timer - T
End Sub

Thử xem tốc độ có bằng mảng 1 chiều với mảng trong mảng hay không!

Nội việc khai báo biến và gán từng mục mà không qua vòng lặp là đã không chuyên nghiệp rồi, thử hỏi duyệt qua việc xử lý bằng vòng lặp thì mỗi mảng mỗi xử lý sao?
 
Lần chỉnh sửa cuối:
Upvote 0
Lấy file của bài 23 và thử với thủ tục này:
Thử xem tốc độ có bằng mảng 1 chiều với mảng trong mảng hay không!

Nghĩa đọc lại bài 30: Nạp mảng xong còn phải xử lý, chứ không phải nạp để đó. Cái code trên ở bài 31 tôi đã test trước khi viết bài. Nhưng tôi dùng offset lần lượt chứ không hì hục viết ra từng range như thế.
Test xong tôi công nhận là nạp mảng trong mảng nhanh hơn 5 đến 6%. Nhưng nếu truy xuất và xử lý chậm hơn 1 vài % (nếu), thì cần phải cân nhắc. Có khi cái tiết kiệm 5% không đủ bù 1% việc xử lý.

Nội việc khai báo biến và gán từng mục mà không qua vòng lặp là đã không chuyên nghiệp rồi, thử hỏi duyệt qua việc xử lý bằng vòng lặp thì mỗi mảng mỗi xử lý sao?

Nếu cần xử lý tất cả 20 mảng, thì mỗi mảng mỗi xử lý, chả lẽ mảng trong mảng thì xử lý ít mảng hơn?
 
Upvote 0
Nghĩa đọc lại bài 30: Nạp mảng xong còn phải xử lý, chứ không phải nạp để đó. Cái code trên ở bài 31 tôi đã test trước khi viết bài. Nhưng tôi dùng offset lần lượt chứ không hì hục viết ra từng range như thế.
Test xong tôi công nhận là nạp mảng trong mảng nhanh hơn 5 đến 6%. Nhưng nếu truy xuất và xử lý chậm hơn 1 vài % (nếu), thì cần phải cân nhắc. Có khi cái tiết kiệm 5% không đủ bù 1% việc xử lý.



Nếu cần xử lý tất cả 20 mảng, thì mỗi mảng mỗi xử lý, chả lẽ mảng trong mảng thì xử lý ít mảng hơn?

Xử lý thì chỉ xử lý 1 vài cột ở trong CSDL để lọc gì gì đó, sau đó tạo một mảng mới. Nếu dùng 20 cột để tạo ra một mảng mới sao làm vòng lặp được? Còn mảng 1 chiều thì rất ngắn gọn khi sử dụng vòng lặp.

Nên nhớ logic là thế này, đầu vào nhanh thì đầu ra sẽ nhanh.
 
Upvote 0
Nếu xử lý 1 vài cột, thì xử lý vài mảng, chứ chả lẽ mảng trong mảng xử lý ít mảng con hơn? Bên trong mảng 1 chiều bên ngoài dùng để chứa, cũng là những mảng, số lượng mảng bằng nhau, các mảng y hệt nhau, chứ khác gì?

Còn đầu vào nhanh dẫn đến đầu ra nhanh thì chưa chắc. Nghĩa cứ xem lại topic thi, cùng 1 tác giả, cùng 1 thuật toán, cùng là Dic (hoặc Collection), cái nào nhanh hơn.

(Tôi đi nghỉ đây, không tranh luận với kẻ cãi ngang nữa)
 
Upvote 0
Nếu xử lý 1 vài cột, thì xử lý vài mảng, chứ chả lẽ mảng trong mảng xử lý ít mảng con hơn? Bên trong mảng 1 chiều bên ngoài dùng để chứa, cũng là những mảng, số lượng mảng bằng nhau, các mảng y hệt nhau, chứ khác gì?

Còn đầu vào nhanh dẫn đến đầu ra nhanh thì chưa chắc. Nghĩa cứ xem lại topic thi, cùng 1 tác giả, cùng 1 thuật toán, cùng là Dic (hoặc Collection), cái nào nhanh hơn.

(Tôi đi nghỉ đây, không tranh luận với kẻ cãi ngang nữa)
Thôi, bây giờ từ đơn giản đến nâng cao đi, nói có sách chứ tranh cãi mà không chứng cứ như Sư phụ thì mệt lắm, bằng chứng đã đưa ra nhiều ở bài trước rồi mà Sư phụ chỉ có nói không à.

Bài này là như vầy (cũng lấy file của bài 23, insert thêm 1 sheet nữa để gán mảng đã xử lý), lấy 20 cột của Sư phụ ra mà làm với bài này:

Đơn giản: Lọc cột A, lấy những ô có chứa số 0 rồi lấy dữ liệu dựa trên các Record đó cho tất cả CSDL (tức 20 cột và n hàng đã được xử lý). Sau đó gán mảng đã xử lý vào trong sheet2 xem tốc độ thế nào! Lưu ý: Không được chừa hàng trống trong mảng đã xử lý!

Code của em để thử đây:

Mã:
Sub Test12()
    Dim T As Double
    T = Timer
    Dim Arr(0 To 19), GetRow(), ArrResult()
    Dim c As Byte, n As Long, r As Long
    With Sheet1.Range("A2:A65535")
        For c = 0 To 19
            Arr(c) = .Offset(, c)
        Next
    End With
    
    For r = 1 To UBound(Arr(0))
        If Arr(0)(r, 1) [COLOR=#ff8c00][B]Like "*0*"[/B][/COLOR] Then
            n = n + 1
            ReDim Preserve GetRow(1 To n)
            GetRow(n) = r
        End If
    Next
    
    If n Then
        ReDim ArrResult(1 To n, 0 To 19)
        For c = 0 To 19
            For r = 1 To n
                ArrResult(r, c) = Arr(c)(GetRow(r), 1)
            Next
        Next
        Sheet2.Range("A2").Resize(n, 20) = ArrResult
    End If
    MsgBox Timer - T
End Sub

Rồi, xin mời code với 20 mảng của Sư phụ!
 
Lần chỉnh sửa cuối:
Upvote 0
1. Tôi nói lại cho rõ, và từng chữ của tôi đều có ý nghĩa: (trích bài 24)

Truy xuất,
xét điều kiện,
và tính toán
đối với mảng trong mảng
vẫn
chưa
phải là tối ưu.


Đọc thiếu 1 chữ thì đừng cãi. Code bài 35 chỉ mới truy xuất và xét điều kiện chứ chưa tính toán.

2. "Mảng trong mảng chưa tối ưu", là phải xét nhiều yếu tố:

a. Hiệu quả:
- tốc độ,
- tính toán chính xác,
- kết quả đầy đủ,
- dễ sửa chữa

b. Hoàn cảnh:
- Lấy bao nhiêu cột trong tổng số cột (5/20, 20/20)
- Mảng mẹ ít phần tử (20), mảng con nhiều phần tử (65000)
- Mảng mẹ nhiều phần tử (50000), mảng con ít phần tử (10 - 20)
- Mảng mẹ nhiều phần tử, mảng con cũng nhiều phần tử
- Dữ liệu 65.000 dòng hay 500 ngàn, 1 triệu dòng

Để test đầy đủ thì thực hiện lại trong topic [THI] 65.000 dòng. mở rộng 1 triệu dòng, chứ code bài 35 không đủ yếu tố để kiểm tra việc "tối ưu"

Thôi, bây giờ từ đơn giản đến nâng cao đi, nói có sách chứ tranh cãi mà không chứng cứ như Sư phụ thì mệt lắm, bằng chứng đã đưa ra nhiều ở bài trước rồi mà Sư phụ chỉ có nói không à.



3. Nhắc lại bài 26: Tôi có đưa chứng cứ

4. Nói thêm: Bài 31 Nghĩa viết:

Nội việc khai báo biến và gán từng mục mà không qua vòng lặp là đã không chuyên nghiệp rồi, thử hỏi duyệt qua việc xử lý bằng vòng lặp thì mỗi mảng mỗi xử lý sao?

Đưa vào vòng lặp 1 cách "Chuyên nghiệp" như thế thì làm sao làm được chuyện này:

Nghĩa (bài 34) đã viết:
Với mảng 1 chiều chúng ta còn linh hoạt hơn khi đảo cột ở các vị trí khác nhau để dễ dàng tạo một nguồn dữ liệu mới để vòng lặp thực hiện nhanh chóng, nhất là trong các vấn đề lọc dữ liệu.

Cái chỗ màu đỏ, nếu bài toán cần xét điều kiện cột 2, trích xuất và tính toán các cột có thứ tự là 7 ,9, 8, 11 (giống trong topic [THI], thì Nghĩa thử "chuyên nghiệp" đi.

Tôi không tranh luận và cũng không thử test gì nữa. Nhất là dữ liệu mẫu kiểu đó.
 
Upvote 0
1. Tôi nói lại cho rõ, và từng chữ của tôi đều có ý nghĩa: (trích bài 24)

Truy xuất,
xét điều kiện,
và tính toán
đối với mảng trong mảng
vẫn
chưa
phải là tối ưu.


Đọc thiếu 1 chữ thì đừng cãi. Code bài 35 chỉ mới truy xuất và xét điều kiện chứ chưa tính toán.

2. "Mảng trong mảng chưa tối ưu", là phải xét nhiều yếu tố:

a. Hiệu quả:
- tốc độ,
- tính toán chính xác,
- kết quả đầy đủ,
- dễ sửa chữa

b. Hoàn cảnh:
- Lấy bao nhiêu cột trong tổng số cột (5/20, 20/20)
- Mảng mẹ ít phần tử (20), mảng con nhiều phần tử (65000)
- Mảng mẹ nhiều phần tử (50000), mảng con ít phần tử (10 - 20)
- Mảng mẹ nhiều phần tử, mảng con cũng nhiều phần tử
- Dữ liệu 65.000 dòng hay 500 ngàn, 1 triệu dòng

Để test đầy đủ thì thực hiện lại trong topic [THI] 65.000 dòng. mở rộng 1 triệu dòng, chứ code bài 35 không đủ yếu tố để kiểm tra việc "tối ưu"





3. Nhắc lại bài 26: Tôi có đưa chứng cứ

4. Nói thêm: Bài 31 Nghĩa viết:



Đưa vào vòng lặp 1 cách "Chuyên nghiệp" như thế thì làm sao làm được chuyện này:



Cái chỗ màu đỏ, nếu bài toán cần xét điều kiện cột 2, trích xuất và tính toán các cột có thứ tự là 7 ,9, 8, 11 (giống trong topic [THI], thì Nghĩa thử "chuyên nghiệp" đi.

Tôi không tranh luận và cũng không thử test gì nữa. Nhất là dữ liệu mẫu kiểu đó.

Tôi ghét nhất là nói mà không làm! Cảm thấy làm không được hay rườm rà hay chậm hơn thì nói đại đi.
 
Upvote 0
Tôi ghét nhất là nói mà không làm! Cảm thấy làm không được hay rườm rà hay chậm hơn thì nói đại đi.
Còn tôi ghét nhất là không chịu đọc. Nếu đọc kỹ thì sẽ thấy tôi không chê bai bất cứ thứ gì trong topic này, tôi chỉ mở rộng nó ra.
Tôi cũng ghét chỗ cứ tưởng người ta chê bai hay ném đá mình rồi cắn càn.

Đọc bài 37, suy gẫm, và tự trả lời thành thật với lương tâm mục số 1, 2 xem tôi có chê bai không, xem mục số 3, 4 có phải là cắn càn hay không.
 
Upvote 0
Còn tôi ghét nhất là không chịu đọc. Nếu đọc kỹ thì sẽ thấy tôi không chê bai bất cứ thứ gì trong topic này, tôi chỉ mở rộng nó ra.
Tôi cũng ghét chỗ cứ tưởng người ta chê bai hay ném đá mình rồi cắn càn.

Đọc bài 37, suy gẫm, và tự trả lời thành thật với lương tâm mục số 1, 2 xem tôi có chê bai không, xem mục số 3, 4 có phải là cắn càn hay không.

Với bài thi đó cũng chẳng là gì là ghê gớm bởi chỉ có 12 mục thì làm sao so sánh với vài chục ngàn mục để tính?

Nhưng với bài này kết quả nó lọc đến trên 22 ngàn dòng, vậy mới nói chuyện nhanh chậm.

Đưa một CSDL nào thực tế đi rồi thử xem sao! Bởi đầu vào nó nhanh chắc chắn đầu ra nó sẽ nhanh.
 
Lần chỉnh sửa cuối:
Upvote 0
Với bài thi đó cũng chẳng là gì là ghê gớm bởi chỉ có 12 mục thì làm sao so sánh với vài chục ngàn mục để tính?

Nhưng với bài này kết quả nó lọc đến trên 22 ngàn dòng, vậy mới nói chuyện nhanh chậm.

Đưa một CSDL nào thực tế đi rồi thử xem sao! Bởi đầu vào nó nhanh chắc chắn đầu ra nó sẽ nhanh.

Dữ liệu mẫu giống topic [THI] với 1 triệu dòng data, danh mục 13.000 đã có sẵn. Tìm đi.
 
Upvote 0
Đưa một CSDL nào thực tế đi rồi thử xem sao! Bởi đầu vào nó nhanh chắc chắn đầu ra nó sẽ nhanh.

Về tốc độ nhanh gấp 2 lần thì tôi không tin.
Bạn đã thử mấy lần?

Nếu code1 chạy mất vd. 0,6 s còn code2 chạy mất 0,3 s thì chưa hẳn là code2 chạy nhanh gấp 2 lần code1. Vì rất có thể 0,3 = 0,6 - 0,3 có thể không đổi khi số dòng cột tăng lên.
Nói nôm na thì với số cột 20 và dòng 20000 thì hiệu 2 thời gian cũng xấp xỉ với hiệu 2 thời gian khi số cột là 20 và số dòng là 50000. Xấp xỉ có nghĩ là có thể có tăng khi số dòng cột tăng nhưng chỉ một % nào đó thôi. Chứ không hẳn tăng gấp đôi hay tăng tỷ lệ thuận với số dòng, cột.
Với máy cũ kỹ của tôi thì với 20 cột và 50000 dòng thì cách mảng trong mảng 1 chiều nạp mất trung bình 0,984, cách mảng 2 chiều nạp mất 1,177

Làm gì có nhanh gấp đôi?

Mà bạn nên tính tỉ lệ. Cũng là 500 nhưng có lúc nó chả là gì cả, chả đáng bõ công xoay xở.

Ở ngay dưới nhà bạn có thể mua bao thuốc rẻ hơn ngoài đầu phố 1000 ₫. Nếu bạn thất nghiệp thì từng ₫ có giá trị, bạn sẽ đi thêm vài bước, tác dụng phụ là sau 1 tháng bạn thấy khỏe hẳn lên, phong độ hơn. Nhưng nếu bạn mỗi tháng làm ra bạc tỷ thì tôi nghĩ có lẽ bạn sẽ mua ngay dưới nhà. Tiện lợi, tiết kiệm thời gian. Và lười đi nữa. Gì chứ con người rất khó chăm nhưng rất dễ lười.

Đối với tỷ phú thì 1000 ₫ chả là cái gì cả. Với code bìh thường chạy hết 30 s thì chuyện tiết kiệm 0,03 s chả là cái gì cả.

Nhưng liệu có thể tiết kiệm được không??? THì kiểm chứng thôi. Xin mời sang phần 2.
--------------
Về ý của anh ptm0412 thì nếu bạn cứ muốn cụ thể để test cho đã thì ...

Tôi có vấn đề cụ thể thế này. Cho trước vùng dữ liệu 20 cột và 50000 dòng. Trước hết chạy Sub FillRange để có vùng như thế. Vấn đề của tôi là cần duyệt từng cell. Nếu giá trị của cell > 20000 thì trừ đi 1, nếu < 20000 thì cộng thêm 1, còn nếu không thì để nguyên.

Ở dưới tôi viết đại 1 code đọc dữ liệu vào mảng 2 chiều rồi "duyệt + tính toán + đập kết quả xuống sheet2".

Bạn hãy viết thêm code của bạn và làm các việc trên.

Bạn nên nhớ là tôi tính tổng thời gian làm công việc chứ không chỉ đọc dữ liệu vào mảng. Tức thời gian = đọc từ sheet1 vào mảng + duyệt + tính toán + đập kết quả xuống sheet2

Bạn ghép 2 code vào cùng 1 tập tin và bạn hãy test kỹ rồi cho kết quả nhé. Tôi không tin là cách của bạn nhanh hơn.

Có thể bạn sẽ bị bất ngờ chăng?

Mã:
Private Declare Function GetTickCount Lib "kernel32" () As Long

Sub FillRange()
Dim r As Long, c As Long, Arr(1 To 50000, 1 To 20) As Long
    Randomize
    For r = 1 To 50000
        For c = 1 To 20
            Arr(r, c) = (50000 * Rnd) + 1
        Next
    Next
    sheet1.Range("A1:T50000").value = Arr
End Sub

Sub test1()
Dim r As Long, c As Long, value As Long, Arr()
    t = GetTickCount
    Arr = sheet1.Range("A1:T50000").value
    
    Debug.Print "nhap mang 2 chieu: " & (GetTickCount - t) / 1000
    
    For r = 1 To 50000
        For c = 1 To 20
            value = Arr(r, c)
            If value > 20000 Then
                Arr(r, c) = value - 1
            ElseIf value < 20000 Then
                Arr(r, c) = value + 1
            End If
        Next
    Next
    
    sheet2.Range("A1:T50000").value = Arr
    
    Debug.Print "test1: " & (GetTickCount - t) / 1000
End Sub
 
Upvote 0
Không quan tâm số dư đầu kỳ, tính từ 01/01/2013 đến 31/12/2013
Tôi dùng thuật toán cũ của bài 1 trong topic http://www.giaiphapexcel.com/forum/...i-tốc-độ-nhanh-nhất-dữ-liệu-hơn-1-triệu-dòng

1. Cùng thuật toán:
- Dùng 1 Dic
- 1 vòng lặp duyệt đủ 1.048.000 dòng
- Có xét điều kiện ngày, mặc dù không cần thiết

2. Hai phương pháp tạo mảng nguồn Data:
- Tạo 5 mảng, mỗi mảng 2 chiều
- Tạo 1 mảng 1 chiều 5 phần tử, mỗi phần tử là 1 mảng 2 chiều (mảng trong mảng)

Kết quả:

Dictionary​
| |
mảng trong mảng | 5 mảng đơn |
ptm0412
|
ptm0412
|
4.862,537
|
4.139,352
|
4.888,26261185451​
|
4.185,41640266332​
|
4.864,64037769323​
|
4.141,88735601126​
|
4.868,12714191808​
|
4.115,22031232163​
|
4.873,01657120655​
|
4.139,70306648835​
|
4.855,86272454248​
|
4.138,20440020708​
|
4.849,42680291159​
|
4.157,85358033923​
|
4.861,59312449752​
|
4.129,84286869791​
|
4.867,71032208583​
|
4.117,71075845511​
|
4.846,01753785154​
|
4.128,44823282704​
|
4.850,71461560938​
|
4.139,23527873692​
|
 
Lần chỉnh sửa cuối:
Upvote 0
...
Với code bình thường chạy hết 30 s thì chuyện tiết kiệm 0,03 s chả là cái gì cả.

Nhưng liệu có thể tiết kiệm được không???
--------------

Chính vì thế nên trong bài ở trên tôi có viết và lập lại đến mấy lần:
- Nạp dữ liệu vào mảng để xử lý chứ không phải nạp để đó
- Nạp mảng tiết kiệm 5% không đủ bù xử lý mảng chậm hơn 1%

Cám ơn anh siwtom đã chịu khó đọc.
 
Upvote 0
Về tốc độ nhanh gấp 2 lần thì tôi không tin.
Bạn đã thử mấy lần?

Nếu code1 chạy mất vd. 0,6 s còn code2 chạy mất 0,3 s thì chưa hẳn là code2 chạy nhanh gấp 2 lần code1. Vì rất có thể 0,3 = 0,6 - 0,3 có thể không đổi khi số dòng cột tăng lên.
Nói nôm na thì với số cột 20 và dòng 20000 thì hiệu 2 thời gian cũng xấp xỉ với hiệu 2 thời gian khi số cột là 20 và số dòng là 50000. Xấp xỉ có nghĩ là có thể có tăng khi số dòng cột tăng nhưng chỉ một % nào đó thôi. Chứ không hẳn tăng gấp đôi hay tăng tỷ lệ thuận với số dòng, cột.
Với máy cũ kỹ của tôi thì với 20 cột và 50000 dòng thì cách mảng trong mảng 1 chiều nạp mất trung bình 0,984, cách mảng 2 chiều nạp mất 1,177

Làm gì có nhanh gấp đôi?

Mà bạn nên tính tỉ lệ. Cũng là 500 nhưng có lúc nó chả là gì cả, chả đáng bõ công xoay xở.

Ở ngay dưới nhà bạn có thể mua bao thuốc rẻ hơn ngoài đầu phố 1000 ₫. Nếu bạn thất nghiệp thì từng ₫ có giá trị, bạn sẽ đi thêm vài bước, tác dụng phụ là sau 1 tháng bạn thấy khỏe hẳn lên, phong độ hơn. Nhưng nếu bạn mỗi tháng làm ra bạc tỷ thì tôi nghĩ có lẽ bạn sẽ mua ngay dưới nhà. Tiện lợi, tiết kiệm thời gian. Và lười đi nữa. Gì chứ con người rất khó chăm nhưng rất dễ lười.

Đối với tỷ phú thì 1000 ₫ chả là cái gì cả. Với code bìh thường chạy hết 30 s thì chuyện tiết kiệm 0,03 s chả là cái gì cả.

Nhưng liệu có thể tiết kiệm được không??? THì kiểm chứng thôi. Xin mời sang phần 2.
--------------
Về ý của anh ptm0412 thì nếu bạn cứ muốn cụ thể để test cho đã thì ...

Tôi có vấn đề cụ thể thế này. Cho trước vùng dữ liệu 20 cột và 50000 dòng. Trước hết chạy Sub FillRange để có vùng như thế. Vấn đề của tôi là cần duyệt từng cell. Nếu giá trị của cell > 20000 thì trừ đi 1, nếu < 20000 thì cộng thêm 1, còn nếu không thì để nguyên.

Ở dưới tôi viết đại 1 code đọc dữ liệu vào mảng 2 chiều rồi "duyệt + tính toán + đập kết quả xuống sheet2".

Bạn hãy viết thêm code của bạn và làm các việc trên.

Bạn nên nhớ là tôi tính tổng thời gian làm công việc chứ không chỉ đọc dữ liệu vào mảng. Tức thời gian = đọc từ sheet1 vào mảng + duyệt + tính toán + đập kết quả xuống sheet2

Bạn ghép 2 code vào cùng 1 tập tin và bạn hãy test kỹ rồi cho kết quả nhé. Tôi không tin là cách của bạn nhanh hơn.

Có thể bạn sẽ bị bất ngờ chăng?

Mã:
Private Declare Function GetTickCount Lib "kernel32" () As Long

Sub FillRange()
Dim r As Long, c As Long, Arr(1 To 50000, 1 To 20) As Long
    Randomize
    For r = 1 To 50000
        For c = 1 To 20
            Arr(r, c) = (50000 * Rnd) + 1
        Next
    Next
    sheet1.Range("A1:T50000").value = Arr
End Sub

Sub test1()
Dim r As Long, c As Long, value As Long, Arr()
    t = GetTickCount
    Arr = sheet1.Range("A1:T50000").value
    
    Debug.Print "nhap mang 2 chieu: " & (GetTickCount - t) / 1000
    
    For r = 1 To 50000
        For c = 1 To 20
            value = Arr(r, c)
            If value > 20000 Then
                Arr(r, c) = value - 1
            ElseIf value < 20000 Then
                Arr(r, c) = value + 1
            End If
        Next
    Next
    
    sheet2.Range("A1:T50000").value = Arr
    
    Debug.Print "test1: " & (GetTickCount - t) / 1000
End Sub

Mã:
Sub test2()
    Dim r As Long, c As Long, value As Long
    Dim Arr(0 To 19), ArrKQ(1 To 50000, 0 To 19)
    t = GetTickCount
    With Sheet1.Range("A1:A50000")
        For c = 0 To 19
            Arr(c) = .Offset(, c)
        Next
    End With
    
    Debug.Print "nhap mang 1 chieu: " & (GetTickCount - t) / 1000
    
    For c = 0 To 19
        For r = 1 To 50000
            value = Arr(c)(r, 1)
            If value > 20000 Then
                ArrKQ(r, c) = value - 1
            ElseIf value < 20000 Then
                ArrKQ(r, c) = value + 1
            End If
        Next
    Next


    Sheet2.Range("A1:T50000").value = ArrKQ
    
    Debug.Print "test2: " & (GetTickCount - t) / 1000
End Sub

Từ việc gán dữ liệu vào mảng một chiều với 20 cột nhanh hơn gán vào mảng 2 chiều, sau đó xử lý với mảng 2 chiều (cả 2 đều có thời gian ngang nhau) ==> Dùng mảng 1 chiều cho lần gán ban đầu sẽ nhanh hơn.
 
Upvote 0
Mã:
Sub test2()
    Dim r As Long, c As Long, value As Long
    Dim Arr(0 To 19), ArrKQ(1 To 50000, 0 To 19)
    t = GetTickCount
    With Sheet1.Range("A1:A50000")
        For c = 0 To 19
            Arr(c) = .Offset(, c)
        Next
    End With
    
    Debug.Print "nhap mang 1 chieu: " & (GetTickCount - t) / 1000
    
    For c = 0 To 19
        For r = 1 To 50000
            value = Arr(c)(r, 1)
            If value > 20000 Then
                ArrKQ(r, c) = value - 1
            ElseIf value < 20000 Then
                ArrKQ(r, c) = value + 1
            End If
        Next
    Next


    Sheet2.Range("A1:T50000").value = ArrKQ
    
    Debug.Print "test2: " & (GetTickCount - t) / 1000
End Sub

Từ việc gán dữ liệu vào mảng một chiều với 20 cột nhanh hơn gán vào mảng 2 chiều, sau đó xử lý với mảng 2 chiều (cả 2 đều có thời gian ngang nhau) ==> Dùng mảng 1 chiều cho lần gán ban đầu sẽ nhanh hơn.

Tôi chưa phán gì cả. Chưa nói cái nào nhanh hơn, và nếu nhanh hơn thì có tới mức phải bận tâm hay không. Vì kiểu nhanh hơn mà hiệu tuyệt đối nó còn nhỏ hơn cả sai số của dụng cụ đo, độ dao động của system v...v thì quên đi cho khỏe.

Tôi tưởng bạn sẽ test vì bạn đòi cụ thể. Nhưng rút cục bạn không test mà chỉ kết luận thôi. Mà kết luận của bạn thì tôi biết từ những bài trước rồi. Khỏi phải nhắc lại.

Riêng code bạn đưa thì những ô có giá trị 20000 sẽ bị mất và không xuất hiện trong sheet2

Ngoài ra bạn còn dùng thêm mảng 2 chiều. Chả nhẽ việc cần làm đòi hỏi vd. 5 mảng 2 chiều thì bạn định biến thành dùng 5 mảng một chiều mà mổi phần tử là mảng 2 chiều + 5 mảng 2 chiều?

Thực ra tôi cũng chả quan tâm tới chuyện này nên nghỉ ở đây thôi.
 
Upvote 0
Tôi chưa phán gì cả. Chưa nói cái nào nhanh hơn, và nếu nhanh hơn thì có tới mức phải bận tâm hay không. Vì kiểu nhanh hơn mà hiệu tuyệt đối nó còn nhỏ hơn cả sai số của dụng cụ đo, độ dao động của system v...v thì quên đi cho khỏe.

Tôi tưởng bạn sẽ test vì bạn đòi cụ thể. Nhưng rút cục bạn không test mà chỉ kết luận thôi. Mà kết luận của bạn thì tôi biết từ những bài trước rồi. Khỏi phải nhắc lại.

Riêng code bạn đưa thì những ô có giá trị 20000 sẽ bị mất và không xuất hiện trong sheet2

Ngoài ra bạn còn dùng thêm mảng 2 chiều. Chả nhẽ việc cần làm đòi hỏi vd. 5 mảng 2 chiều thì bạn định biến thành dùng 5 mảng một chiều mà mổi phần tử là mảng 2 chiều + 5 mảng 2 chiều?

Thực ra tôi cũng chả quan tâm tới chuyện này nên nghỉ ở đây thôi.

Mặc dù thiếu dữ kiện màu đỏ vì sơ ý, nhưng nếu thêm vô cũng đảm bảo không thể chậm hơn!

Mã:
    For c = 0 To 19
        For r = 1 To 50000
            value = Arr(c)(r, 1)
            If value > 20000 Then
                ArrKQ(r, c) = value - 1
            ElseIf value < 20000 Then
                ArrKQ(r, c) = value + 1
[COLOR=#ff0000]            Else[/COLOR]
[COLOR=#ff0000]                ArrKQ(r, c) = 20000[/COLOR]
            End If


        Next
    Next

Ngoài ra bạn còn dùng thêm mảng 2 chiều. Chả nhẽ việc cần làm đòi hỏi vd. 5 mảng 2 chiều thì bạn định biến thành dùng 5 mảng một chiều mà mổi phần tử là mảng 2 chiều + 5 mảng 2 chiều?

Bình thường thôi, người ta thường nói "dụng nhân như dụng mộc", tùy theo "gỗ" xấu tốt thế nào mà dùng vào việc gì thôi, không ai lại làm một cách bất di bất dịch một loại "gỗ" để làm nhiều sản phẩm khác nhau cả.

Chẳng hạn, trong chừng mực, mọi người phải thừa nhận là dùng mảng 1 chiều để thực hiện như bài mình giới thiệu phải nhanh hơn những cách khác. Đồng thời, khi một CSDL cần các cột lẻ của 20 cột kia, tức từ 1, 3, 5, 7, ... 19 thì sao? Ứng dụng cho bài này phải quá tốt không?
 
Upvote 0
Bình thường thôi, người ta thường nói "dụng nhân như dụng mộc", tùy theo "gỗ" xấu tốt thế nào mà dùng vào việc gì thôi, không ai lại làm một cách bất di bất dịch một loại "gỗ" để làm nhiều sản phẩm khác nhau cả.

Chẳng hạn, trong chừng mực, mọi người phải thừa nhận là dùng mảng 1 chiều để thực hiện như bài mình giới thiệu phải nhanh hơn những cách khác. Đồng thời, khi một CSDL cần các cột lẻ của 20 cột kia, tức từ 1, 3, 5, 7, ... 19 thì sao? Ứng dụng cho bài này phải quá tốt không?

Tôi và anh ptm0412 chỉ góp ý thêm thôi. Nhưng bạn lại cho là chỉ trích, tấn công.
Thôi, nói thế là đủ rồi.
 
Upvote 0
......
Bình thường thôi, người ta thường nói "dụng nhân như dụng mộc", tùy theo "gỗ" xấu tốt thế nào mà dùng vào việc gì thôi, không ai lại làm một cách bất di bất dịch một loại "gỗ" để làm nhiều sản phẩm khác nhau cả.
....

Câu này vận đúng vào với topic này HTN ah, ngay từ cái tên "Thủ thuật ..." cũng phải xem xét có đúng không nữa ah

Đừng vội kết luận vội vàng điều gì, khi chính mình chưa hiểu chưa quét hết cảc trường hợp chưa hiểu bản chất vấn đề

Ai ai cũng biết kiểu không hiểu, chưa làm chưa quét hết các trường hợp mà kết luận như đúng rồi - thì hí họa may ra đúng còn 90% là chệch -- vậy nên chừng nào viết ra điều gì kết luận thì phải thí nghiệm, phải hiểu bản chất vấn đề đã - mà có khi cũng chỉ dám viết cho chính mình mà thui -- để vài tháng sau có khi lại ah ồ .... lại không đúng rùi .....

..
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi và anh ptm0412 chỉ góp ý thêm thôi. Nhưng bạn lại cho là chỉ trích, tấn công.
Thôi, nói thế là đủ rồi.
Em không cho là chỉ trích hay tấn công, cái đơn giản là nhiều người theo cách làm cũ họ không thừa nhận hoặc đưa ra các tình huống bắt bí nhau thôi, chứ như bài mà em thử với lọc dữ liệu có chứa 0 của file ở bài 23 thì cũng thừa hiểu code nào nhanh hơn code nào, code nào rườm rà hơn code nào. Hoặc lấy code tạo dãy số của Thầy chỉ lấy các cột chẳn hoặc cột lẽ rồi thêm -1 hoặc +1 như trên, thử xem có phải ứng dụng vào cách dùng mảng 1 chiều tốt hơn không! Thêm nữa Thầy nói bất ngờ, khi em làm theo kiểu của em tốc độ cũng nhanh hơn của Thầy, em cũng chẳng bất ngờ gì.

Cách thức thì đã giới thiệu và đã chứng minh nó hiệu quả (không nói nó tối ưu), còn áp dụng thì tùy trường hợp mà dùng hợp lý thôi, giết gà đâu cần phải dùng dao mỗ trâu đâu.

Áp dụng nó cho trường hợp bài này:

http://www.giaiphapexcel.com/forum/...õichổ-nào-không-chịu-chạy&p=564964#post564964

Phải chăng là hợp lý không vì các cột họ cần lọc đâu phải tất cả dữ liệu!?
 
Lần chỉnh sửa cuối:
Upvote 0
Riêng code bạn đưa thì những ô có giá trị 20000 sẽ bị mất và không xuất hiện trong sheet2
Đối với việc test code của mình, tôi đã làm cẩn thận, việc test của người khác thì tôi phải cẩn thận gấp đôi. Cái kết quả tôi đưa lên trong bài 44, tôi đã test rất cẩn thận:

1. Để có kết quả bình quân 10 lần, tôi test trên 30 lần cho mỗi code, bảo đảm sai biệt giữa các lần tính bình quân dưới 50 ms
2. Đối chiếu kết quả 2 code để bảo đảm 2 code thực hiện những việc như nhau:
- Đếm số dòng của 2 kết quả
- Tính tổng từng cột của 2 kết quả và so với nhau (6 cột)
- So hàng ngang giống nhau từng dòng một (1.300 dòng)

Nghĩa là viết 10 phút, test gần 1 giờ. (Viết 10 phút vì code của tôi có sẵn trong bài 1 topic bên kia, chỉ dùng 10 phút để chuyển dạng mảng nạp vào và cách truy xuất mảng, mọi thứ để nguyên)

Mặc dù vậy cũng không dám tuyên bố như đinh đóng cột, lúc nào tôi cũng phát biểu thận trọng "chưa" thay vì "không", "có thể" thay vì "chắc chắn", ...

Câu phát biểu "theo logic đầu vào nhanh thì đầu ra nhanh" tôi cũng không dám bắt bẻ ngay lập tức vì còn phải chờ ý kiến vài người khác nữa, dù rằng tôi nghi ngờ cái "logic" đó. Tôi chỉ nói "chưa chắc"

Đúng như vodoi2x nói:
Đừng vội kết luận vội vàng điều gì, khi chính mình chưa hiểu chưa quét hết cảc trường hợp chưa hiểu bản chất vấn đề

Chỉ có 1 câu phát biểu này là tôi dám xổ toẹt ngay:
"việc khai báo biến và gán từng mục mà không qua vòng lặp là đã không chuyên nghiệp rồi"

Tôi xổ toẹt vì nó phản lại ngay chính phát biểu trước đó của người phát ngôn:

Với mảng 1 chiều chúng ta còn linh hoạt hơn khi đảo cột ở các vị trí khác nhau để dễ dàng tạo một nguồn dữ liệu mới

Và tôi nói thật, nếu cần truy xuất và xử lý đủ 20/20 cột, tôi cũng không tạo 20 mảng, tôi tạo 1 mảng 20 cột. Còn nếu chỉ dùng 1 số cột trong 20 cột thôi, tôi mới tạo các mảng 2 chiều 1 cột riêng rẽ.

Về cấu trúc dữ liệu, việc sử dụng đủ 20/20 cột đã là hiếm hoi, vì phải bỏ đi ít nhất là cột record ID, và bỏ những thông tin không thể hiện trên báo cáo. Các cột không dùng đó sẽ thể hiện trên báo cáo khác, khi đó mới cần dùng.
Bộ cơ sở dữ liệu của anh Tuân trong topic [THI], sẽ ra ít nhất 4 loại báo cáo:
- Báo cáo nhập xuất tồn chung các kho (như đề thi)
- Báo cáo nhập xuất tồn riêng cho từng kho (vì có 1 cột mã kho)
- Báo cáo số lượng hàng bán cho từng khách hàng (vì có cột mã khách hàng)
- Báo cáo mua hàng của từng nhà cung cấp (vì có cột mã nhà cung cấp)
- Báo cáo chi tiết nhập xuất từng chứng từ của 1 mặt hàng chọn

Một bộ CSDL 20 cột mà phải sử dụng hết để ra 1 cái báo cáo là bộ CSDL không tốt.

Sử dụng 20/20 đã là hiếm như vậy, thì việc sử dụng toàn cột chẵn, toàn cột lẻ, hay cách 2 cột dùng 1 cột theo quy luật, (để có thể dùng vòng lặp), lại là chuyện trên trời. Tôi xổ toẹt vì lý do đó.
 
Upvote 0
Cách thức thì đã giới thiệu và đã chứng minh nó hiệu quả (không nói nó tối ưu)

Thế mà chỉ vì tôi nói 1 câu "chưa tối ưu", đã giãy nảy lên cãi mười lăm hai chục bài liền.
đưa ra các tình huống bắt bí nhau thôi,
Nói tôi bắt bí là sai, bảo tôi dẫn chứng, thì tôi dẫn chứng, bảo tôi cho dữ liệu test, thì tôi chỉ đến đề bài của 1 người thứ 3 cho công bằng.
 
Lần chỉnh sửa cuối:
Upvote 0
Câu phát biểu "theo logic đầu vào nhanh thì đầu ra nhanh" tôi cũng không dám bắt bẻ ngay lập tức vì còn phải chờ ý kiến vài người khác nữa, dù rằng tôi nghi ngờ cái "logic" đó. Tôi chỉ nói "chưa chắc"

Thì cũng đã chứng minh rồi đó thôi!

Chỉ có 1 câu phát biểu này là tôi dám xổ toẹt ngay:
"việc khai báo biến và gán từng mục mà không qua vòng lặp là đã không chuyên nghiệp rồi"

Tôi xổ toẹt vì nó phản lại ngay chính phát biểu trước đó của người phát ngôn:

Với mảng 1 chiều chúng ta còn linh hoạt hơn khi đảo cột ở các vị trí khác nhau để dễ dàng tạo một nguồn dữ liệu mới

Dễ hiểu mà, giả sử có 20 cột, lấy 10 cột ở các số cột: 20, 10, 5, 1, 2, 3, 9, 12, 15, 11 thì làm sao?

Thêm 1 mảng 1 chiều: ArrCot = Array(20, 10, 5, 1, 2, 3, 9, 12, 15, 11)

Rồi, giờ duyệt vòng lặp cho gán vào mảng 1 chiều có 10 phần tử được chưa?

Theo Sư phụ thì làm sao? Đấy mới là thực tế truy xuất, chứ không phải lúc nào cũng bê nguyên cái CSDL vào báo cáo.

Một bộ CSDL 20 cột mà phải sử dụng hết để ra 1 cái báo cáo là bộ CSDL không tốt.

Đúng rồi đó! Vậy mới dùng nhiều cho mảng chứa các cột chứ, chẳng lẽ dùng mảng 2 chiều để "tóm hết" CSDL sao?

Và tôi nói thật, nếu cần truy xuất và xử lý đủ 20/20 cột, tôi cũng không tạo 20 mảng, tôi tạo 1 mảng 20 cột. Còn nếu chỉ dùng 1 số cột trong 20 cột thôi, tôi mới tạo các mảng 2 chiều 1 cột riêng rẽ.

Ủa, ai bắt bẻ việc này vậy? Sau em khi chứng minh là 20 mảng đơn vẫn chậm thì đã nói như trên đúng không?


Bộ cơ sở dữ liệu của anh Tuân trong topic [THI], sẽ ra ít nhất 4 loại báo cáo:

Nói về bài Thi, muốn biết nhanh hay chậm dễ mà, như đã nói, "đầu vào nhanh thì đầu ra sẽ nhanh", Sư phụ cứ lấy CODE của SƯ PHỤ, thử thay mấy cái mảng đơn lấy cột gì đó thành 1 mảng 1 chiều có các phần tử là các cột, rồi sau đó cứ thay thế:

thay vì:

CotXuat(r,1) thì thay vào MangCacCot(ViTri)(r,1)

Chỉ vậy thôi, Và em đã thử chính code của Sư phụ, tốc độ tăng lên đấy! Không tin thì Sư phụ cứ thử ha!
 
Upvote 0
Và cũng nói thêm, tại sao phải dùng mảng 1 chiều để gán các phần tử là các cột như vậy? Đơn giản là HẠN CHẾ KHAI BAO BIẾN TRÀN LAN mà thôi, đồng thời dễ dàng duyệt trong vòng lặp và cũng nhỉn về tốc độ.
 
Upvote 0
Với bài viết này, tôi sẽ giới thiệu cho các bạn sử dụng mảng 1 chiều để chứa các mảng 2 chiều 1 cột thay vì chỉ đơn thuần là mảng 2 chiều chứa tất cả các cột.

Với một CSDL với 20 cột và 65.534 dòng, tôi đã thử nghiệm như sau:

1) Dùng mảng 2 chiều để nhận toàn bộ giá trị của CSDL:

Mã:
Sub Test9()
    Dim T As Double
    T = Timer
    [B][COLOR=#ff0000]Dim Arr()[/COLOR][/B]
    Arr = Sheet1.Range("A2:T65535")
    MsgBox Timer - T
End Sub

2) Dùng mảng 1 chiều để chia nhỏ CSDL thành 20 cột:

Mã:
Sub Test10()
    Dim T As Double
    T = Timer
    Dim Arr(0 To 19)
    Dim c As Byte
    With Sheet1.Range("A2:A65535")
        For c = 0 To 19
            Arr(c) = .Offset(, c)
        Next
    End With
    MsgBox Timer - T
End Sub

Kết quả thực hiện, mảng 1 chiều cho thời gian nhanh gấp đôi mảng 2 chiều! Với mảng 1 chiều chúng ta còn linh hoạt hơn khi đảo cột ở các vị trí khác nhau để dễ dàng tạo một nguồn dữ liệu mới để vòng lặp thực hiện nhanh chóng, nhất là trong các vấn đề lọc dữ liệu.

Tôi luôn nghi ngờ điều này vì không lý gì 10 bọc 1 kg lại khác 1 bọc 10 kg.
Tôi đã thí nghiệm lại bằng cách sửa code Test09 như sau:
Mã:
Sub Test9()
    Dim T As Double
    T = Timer
    [COLOR=#ff0000][B]Dim Arr[/B][/COLOR] ''chứ không phải là Arr()
[B]    Arr = Sheet1.Range("A2:T65535")[/B]
    MsgBox Timer - T
End Sub
Và bây giờ tốc độ đã khác rồi nha!
 
Upvote 0
Nói về bài Thi, muốn biết nhanh hay chậm dễ mà, như đã nói, "đầu vào nhanh thì đầu ra sẽ nhanh", Sư phụ cứ lấy CODE của SƯ PHỤ, thử thay mấy cái mảng đơn lấy cột gì đó thành 1 mảng 1 chiều có các phần tử là các cột, rồi sau đó cứ thay thế:
thay vì:

CotXuat(r,1) thì thay vào MangCacCot(ViTri)(r,1)

Chỉ vậy thôi, Và em đã thử chính code của Sư phụ, tốc độ tăng lên đấy! Không tin thì Sư phụ cứ thử ha!

Đọc bài 44 đi, tôi làm rồi ra kết quả và đã post lên. Tôi vẫn ghét kẻ không đọc bài.

Thêm 1 mảng 1 chiều: ArrCot = Array(20, 10, 5, 1, 2, 3, 9, 12, 15, 11)

Rồi, giờ duyệt vòng lặp cho gán vào mảng 1 chiều có 10 phần tử được chưa?

Lại đẻ ra thêm 1 mảng. Liệu có còn "nhanh gấp đôi" được không?

Nguyên văn bởi ptm0412 Và tôi nói thật, nếu cần truy xuất và xử lý đủ 20/20 cột, tôi cũng không tạo 20 mảng, tôi tạo 1 mảng 20 cột. Còn nếu chỉ dùng 1 số cột trong 20 cột thôi, tôi mới tạo các mảng 2 chiều 1 cột riêng rẽ.
Ủa, ai bắt bẻ việc này vậy? Sau em khi chứng minh là 20 mảng đơn vẫn chậm thì đã nói như trên đúng không?

Vẫn là không đọc bài. Để test code 9 và code 10, tôi phải để nguyên trạng nhận 20 cột để so sánh nên mới xài 20 biến. Lúc bấy giờ, chỉ nhanh hơn 5 - 6 % chứ không phải "gấp đôi". Test để ra kết quả so sánh, chứ không phải để xài.

Nếu xài 5 cột tôi khai báo 5 biến có tên cụ thể để dễ hình dung. Không thể gọi là khai báo tràn lan. Khi viết code cần lấy dữ liệu về số lượng và thành tiền thì lấy biến QtyArr và AmtArr, chứ không cần chạy qua sheet dữ liệu để xem số lượng cột thứ mấy và thành tiền cột thứ mấy, rồi chạy trở lên trên xem cột số đó tương ứng Arr(mấy).
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom