Array: Có thể remove một hay vài hàng bất kỳ mà không dùng vòng lặp được không? (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
Chẳng hạn, tôi có 1 mảng có 10 hàng, giả sử tôi muốn remove hàng 5 và hàng 7 thì trong mảng còn 8 hàng (1,2,3,4,6,8,9,10 theo số hàng ban đầu) và liền kề nhau, không đứt đoạn, nếu không dùng vòng lặp để duyệt thì có được không? Nếu được thì làm như thế nào?

Nó tương tự như Remove Item trong ComboBox hay ListBox, Listview ... vậy.

Cám ơn rất nhiều.
 
Nhớ có 1 lần anh NDU nói là không thể. Không biết đến nay thì có thể hay không.
 
Upvote 0
Chẳng hạn, tôi có 1 mảng có 10 hàng, giả sử tôi muốn remove hàng 5 và hàng 7 thì trong mảng còn 8 hàng (1,2,3,4,6,8,9,10 theo số hàng ban đầu) và liền kề nhau, không đứt đoạn, nếu không dùng vòng lặp để duyệt thì có được không? Nếu được thì làm như thế nào?

Nó tương tự như Remove Item trong ComboBox hay ListBox, Listview ... vậy.

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

Chưa hiểu mục tiêu của em thế nào?
 
Upvote 0
Theo cấu trúc dữ liệu thì đúng là không thể làm thế được trong VBA nhưng có cách khác có thể làm được đó là dùng chức năng của Excel. Cách thức như sau:
Lấy mảng, gán cho một vùng trong Excel, xóa dòng mong muốn và trả lại vùng vào mảng, nhưng yêu cầu là mảng phải định nghĩa là biến kiểu variant trước.
Thiển ý của mình như thế, bạn thử ngâm cứu xem.
 
Upvote 0
Chẳng hạn, tôi có 1 mảng có 10 hàng, giả sử tôi muốn remove hàng 5 và hàng 7 thì trong mảng còn 8 hàng (1,2,3,4,6,8,9,10 theo số hàng ban đầu) và liền kề nhau, không đứt đoạn, nếu không dùng vòng lặp để duyệt thì có được không? Nếu được thì làm như thế nào?

Nó tương tự như Remove Item trong ComboBox hay ListBox, Listview ... vậy.

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

Thì "quăng" mảng vào ListBox rồi Remove Item. Xong lấy List từ ListBox cho ngược vào mảng
 
Upvote 0
Chẳng hạn, tôi có 1 mảng có 10 hàng, giả sử tôi muốn remove hàng 5 và hàng 7 thì trong mảng còn 8 hàng (1,2,3,4,6,8,9,10 theo số hàng ban đầu) và liền kề nhau, không đứt đoạn, nếu không dùng vòng lặp để duyệt thì có được không? Nếu được thì làm như thế nào?

Nó tương tự như Remove Item trong ComboBox hay ListBox, Listview ... vậy.

Cám ơn rất nhiều.
Bóc từng thằng ra, ví dụ bóc dòng 5 và dòng 7 đó ra thay thế cho nó là 1 cái gì đó rồi lọc mãng nó ra là được.
 
Upvote 0
Thì "quăng" mảng vào ListBox rồi Remove Item. Xong lấy List từ ListBox cho ngược vào mảng

Chính xác là em đã từng dùng như thế, nhưng ta đang không dùng những controls này thì làm sao mà "quăng"? Em định sẽ hỏi rằng mình có thể tạo một ComboBox hay ListBox ảo được không?
 
Upvote 0
Chính xác là em đã từng dùng như thế, nhưng ta đang không dùng những controls này thì làm sao mà "quăng"? Em định sẽ hỏi rằng mình có thể tạo một ComboBox hay ListBox ảo được không?

Trong VBA có vài cái ta "ảo" được (chẳng hạn Image List) nhưng vài thứ lại không làm được điều này và ListBox, ComboBox là 1 trong những thứ như thế
Vậy, dù không dùng cũng có thể vẽ trên UserForm hoặc trên bảng tính và giấu nó vào chổ nào đó, mục đích chỉ để lọc Array cũng được vậy
Việc vẽ ListBox, ComboBox có thể làm bằng code ---> Xong việc ta xóa luôn thì sẽ chẳng ai nhìn thấy
 
Upvote 0
Trong VBA có vài cái ta "ảo" được (chẳng hạn Image List) nhưng vài thứ lại không làm được điều này và ListBox, ComboBox là 1 trong những thứ như thế
Vậy, dù không dùng cũng có thể vẽ trên UserForm hoặc trên bảng tính và giấu nó vào chổ nào đó, mục đích chỉ để lọc Array cũng được vậy
Việc vẽ ListBox, ComboBox có thể làm bằng code ---> Xong việc ta xóa luôn thì sẽ chẳng ai nhìn thấy
Có vài dòng ta đâu nhọc công thế, bóc = cách thủ công là filter là được mà.
 
Upvote 0
Trong VBA có vài cái ta "ảo" được (chẳng hạn Image List) nhưng vài thứ lại không làm được điều này và ListBox, ComboBox là 1 trong những thứ như thế
Vậy, dù không dùng cũng có thể vẽ trên UserForm và giấu nó vào chổ nào đó, mục đích chỉ để lọc Array cũng được vậy

Có bao giờ Thầy add item trong listbox và item đó chen ngang ở bất cứ hàng nào trong list đó có được không?
 
Upvote 0
Bóc từng thằng ra, ví dụ bóc dòng 5 và dòng 7 đó ra thay thế cho nó là 1 cái gì đó rồi lọc mãng nó ra là được.

Có vài dòng ta đâu nhọc công thế, bóc = cách thủ công là filter là được mà.

Tôi muốn xử lý trên mảng, đồng thời vẫn giữ cấu trúc của CSDL, không xóa hay sắp xếp gì. Nếu dùng trên mãng rồi gán xuống sheet rồi từ sheet chuyển lại thành mảng thì có thể nói rằng không còn cách nào nữa thì tôi mới dùng đến cách này.
 
Upvote 0
Trong VBA có hàm filter mà bạn, bạn có thể lọc mãng dựa vào hàm này mà.
Cái bạn nói chỉ dùng được đối với mảng 1 chiều thôi
Code dùng Array trên Excel có mấy khi xài thằng 1 chiều này đâu chứ (toàn mảng 2 chiều, lấy gì mà Filter?)
 
Upvote 0
Chẳng hạn, tôi có 1 mảng có 10 hàng, giả sử tôi muốn remove hàng 5 và hàng 7 thì trong mảng còn 8 hàng (1,2,3,4,6,8,9,10 theo số hàng ban đầu) và liền kề nhau, không đứt đoạn, nếu không dùng vòng lặp để duyệt thì có được không? Nếu được thì làm như thế nào?

Nó tương tự như Remove Item trong ComboBox hay ListBox, Listview ... vậy.

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

Dùng các control, property hay ứng dụng nào đó để lưu nháp không nhanh đâu, mặc dù ta không thấy có vòng lặp nhưng biết đâu họ vẫn dùng vòng lặp để sắp xếp lại vị trí của các phần tử. Xử lý nhanh vẫn là thực hiện trong biến nhớ, mảng cũng là biến nhớ nên cũng nhanh. Nhưng để định vị lại vị trí các phần tử trong mảng mà không dùng vòng lặp thì có một cách xử lý là copy các byte của mảng trong bên trong bộ nhớ, làm được cách này thì tốc độ vi vu. Mình đang tìm cách giải quyết vần đề này bằng xử lý trong bộ nhớ, nếu thành công thì khoe hàng ngay.
 
Upvote 0
Chẳng hạn, tôi có 1 mảng có 10 hàng, giả sử tôi muốn remove hàng 5 và hàng 7 thì trong mảng còn 8 hàng (1,2,3,4,6,8,9,10 theo số hàng ban đầu) và liền kề nhau, không đứt đoạn, nếu không dùng vòng lặp để duyệt thì có được không? Nếu được thì làm như thế nào?

Nó tương tự như Remove Item trong ComboBox hay ListBox, Listview ... vậy.

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

Dùng các control, property hay ứng dụng nào đó để lưu nháp không nhanh đâu, mặc dù ta không thấy có vòng lặp nhưng biết đâu họ vẫn dùng vòng lặp để sắp xếp lại vị trí của các phần tử. Xử lý nhanh vẫn là thực hiện trong biến nhớ, mảng cũng là biến nhớ nên cũng nhanh. Nhưng để định vị lại vị trí các phần tử trong mảng mà không dùng vòng lặp thì có một cách xử lý là copy các byte của mảng trong bên trong bộ nhớ, làm được cách này thì tốc độ vi vu. Mình đang tìm cách giải quyết vần đề này bằng xử lý trong bộ nhớ, nếu thành công thì khoe hàng ngay.

Mình đã tìm được giải pháp là xử lý trong bộ nhớ. Đây có lẽ là phương pháp xử lý nhanh nhất. Để làm được điều này cần dùng hàm API CopyMemory () để sao chép các byte trong bộ nhớ.

Bạn có thể copy toàn bộ mã nguồn dưới đây và đưa vào một module để test.

[GPECODE=vb]
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dst As Any, ByVal iLen&)

Function DeleteElementArray2D(arrSource(), ByVal lIndexBegin As Long, ByVal lIndexEnd As Long, Optional ByVal bEraseSource As Boolean = True) As Variant
'Programming by: Nguyen Duy Tuan - www.bluesofts.net
'Return: an array after deleting Element from lIndexBegin to lIndexEnd
Dim I As Long, ilowArray As Integer
ReDim out(UBound(arrSource, 1) - (lIndexEnd - lIndexBegin + 1), UBound(arrSource, 2)) As Variant
ilowArray = LBound(arrSource, 1)
For I = LBound(arrSource, 2) To UBound(arrSource, 2) 'Copy columns
CopyMemory ByVal VarPtr(out(ilowArray, I)), ByVal VarPtr(arrSource(ilowArray, I)), 16 * ((lIndexBegin - ilowArray) + 1)
Next I
For I = LBound(arrSource, 2) To UBound(arrSource, 2)
CopyMemory ByVal VarPtr(out(lIndexBegin, I)), ByVal VarPtr(arrSource(lIndexEnd + 1, I)), 16 * (UBound(arrSource) + 1 - (lIndexEnd + 1))
Next I

'Return array after deleting
DeleteElementArray2D = out

If bEraseSource Then
'Erase source array in memory
For I = LBound(arrSource, 2) To UBound(arrSource, 2)
ZeroMemory ByVal VarPtr(arrSource(0, I)), 16 * (UBound(arrSource) + 1)
Next I
Erase arrSource
End If
End Function
[/GPECODE]

Các bạn có thể download file vể chạy thử.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Mình đã tìm được giải pháp là xử lý trong bộ nhớ. Đây có lẽ là phương pháp xử lý nhanh nhất. Để làm được điều này cần dùng hàm API CopyMemory () để sao chép các byte trong bộ nhớ.

Bạn có thể copy toàn bộ mã nguồn dưới đây và đưa vào một module để test.

[GPECODE=vb]
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dst As Any, ByVal iLen&)

Function DeleteElementArray2D(arrSource(), ByVal lIndexBegin As Long, ByVal lIndexEnd As Long, Optional ByVal bEraseSource As Boolean = True) As Variant
'Programming by: Nguyen Duy Tuan - www.bluesofts.net
'Return: an array after deleting Element from lIndexBegin to lIndexEnd
Dim I As Long, ilowArray As Integer
ReDim out(UBound(arrSource, 1) - (lIndexEnd - lIndexBegin + 1), UBound(arrSource, 2)) As Variant
ilowArray = LBound(arrSource, 1)
For I = LBound(arrSource, 2) To UBound(arrSource, 2) 'Copy columns
CopyMemory ByVal VarPtr(out(ilowArray, I)), ByVal VarPtr(arrSource(ilowArray, I)), 16 * ((lIndexBegin - ilowArray) + 1)
Next I
For I = LBound(arrSource, 2) To UBound(arrSource, 2)
CopyMemory ByVal VarPtr(out(lIndexBegin, I)), ByVal VarPtr(arrSource(lIndexEnd + 1, I)), 16 * (UBound(arrSource) + 1 - (lIndexEnd + 1))
Next I

'Return array after deleting
DeleteElementArray2D = out

If bEraseSource Then
'Erase source array in memory
For I = LBound(arrSource, 2) To UBound(arrSource, 2)
ZeroMemory ByVal VarPtr(arrSource(0, I)), 16 * (UBound(arrSource) + 1)
Next I
Erase arrSource
End If
End Function

Sub FillToRange(rng As Range, arr As Variant, Optional ByVal Is2D As Boolean = True)
'Programming by: Nguyen Duy Tuan - www.bluesofts.net
'Fill array into Range
If Is2D Then '(NumberOfDimensions(arr) > 1)
rng.Resize(UBound(arr, 1) - LBound(arr, 1) + 1, UBound(arr, 2) - LBound(arr, 2) + 1).Value = arr
Else '
rng.Resize(1, UBound(arr, 1) - LBound(arr, 1) + 1).Value = arr
End If
End Sub

Sub TestArray()

Dim X As Long, Y As Long
ReDim Source(0 To 5000, 0 To 5) As Variant

'Tao mang cos du lieu de test
For X = 0 To 5
For Y = 0 To 5000
Source(Y, X) = "Item " & Y & " in col " & X
Next Y
Next X
MsgBox "Fill to range array source."
FillToRange Range("A1"), Source
Dim Dest As Variant

Dest = DeleteElementArray2D(Source, 3, 9)

MsgBox "Fill to range array after deleting Elements from 3 to 9."
FillToRange Range("H1"), Dest
End Sub
[/GPECODE]

Các bạn có thể download file vể chạy thử.
Chào Anh Tuân! sao anh lại cho hệ điều hành Win7 & office 64 bit được về hư vậy, phiềm anh thêm 1 đoạn ngắn cho hệ 64bit chạy được ko ạ

Thân
 
Upvote 0
Mình đã tìm được giải pháp là xử lý trong bộ nhớ. Đây có lẽ là phương pháp xử lý nhanh nhất. Để làm được điều này cần dùng hàm API CopyMemory () để sao chép các byte trong bộ nhớ.

Bạn có thể copy toàn bộ mã nguồn dưới đây và đưa vào một module để test.

Mã:
.........................................

Các bạn có thể download file vể chạy thử.

Đã test, tuyệt vời, có lẽ đây là bài hay nhất mà mình được đọc trên GPE từ tết đến giờ.


đúng rồi đó...................
Lợi dụng để quảng cáo, vớ vẩn quá!
 
Lần chỉnh sửa cuối:
Upvote 0
Mình đã tìm được giải pháp là xử lý trong bộ nhớ. Đây có lẽ là phương pháp xử lý nhanh nhất. Để làm được điều này cần dùng hàm API CopyMemory () để sao chép các byte trong bộ nhớ.
..........................
Bạn có thể copy toàn bộ mã nguồn dưới đây và đưa vào một module để test.
Các bạn có thể download file vể chạy thử.

Rất nhanh và "mượt mà", Cám ơn anh Tuân rất nhiều.

Tuy nhiên, nhìn vào hàm em thấy delete bắt đầu từ A đến Z, vậy nếu ngắt quãng thì phải làm như thế nào? Chẳng hạn có 10 hàng, nhưng chỉ xóa từ hàng 2 đến hàng 5 và hàng 7 thì phải làm thế nào? Mình có thể làm cái ParaArray cho trường hợp này được chứ?
 
Upvote 0
Rất nhanh và "mượt mà", Cám ơn anh Tuân rất nhiều.

Tuy nhiên, nhìn vào hàm em thấy delete bắt đầu từ A đến Z, vậy nếu ngắt quãng thì phải làm như thế nào? Chẳng hạn có 10 hàng, nhưng chỉ xóa từ hàng 2 đến hàng 5 và hàng 7 thì phải làm thế nào? Mình có thể làm cái ParaArray cho trường hợp này được chứ?

Thì làm 2 lần: Xóa hàng 7 trước, xong làm tiếp xóa từ hàng đến 5
Tôi chưa test nhưng theo suy luận logic thì tôi nghĩ phải là như vậy (xóa từ dưới lên)
 
Upvote 0
Rất nhanh và "mượt mà", Cám ơn anh Tuân rất nhiều.

Tuy nhiên, nhìn vào hàm em thấy delete bắt đầu từ A đến Z, vậy nếu ngắt quãng thì phải làm như thế nào? Chẳng hạn có 10 hàng, nhưng chỉ xóa từ hàng 2 đến hàng 5 và hàng 7 thì phải làm thế nào? Mình có thể làm cái ParaArray cho trường hợp này được chứ?

Có thể dùng tham số chuỗi "2-5,7" để xóa dòng 7 và từ 2-5 nhưng chỉ là tiện ích khi ứng dụng, và làm như thế trong hàm phải có nhiều đoạn code xử lý để lấy số dòng cần xoá sau đó mới vào nội dung chính là xoá, nhìn vào code của hàm thấy giảm đi tính trọng tâm là xoá phần tử mảng của hàm? Tốt nhất làm một hàm khác có tham số này, mỗi lần xoá thì dùng hàm DeleteElementArray2D.
 
Upvote 0
Thì làm 2 lần: Xóa hàng 7 trước, xong làm tiếp xóa từ hàng đến 5
Tôi chưa test nhưng theo suy luận logic thì tôi nghĩ phải là như vậy (xóa từ dưới lên)

Để em nghiên cứu hàm của anh Tuân xong em thử cải tiến tổng quát hơn. Chứ làm xong bước đầu chạy 5000 vòng lặp, lại làm bước 2, lại chạy thêm 5000 vòng lặp, nếu N bước thì chạy mất đúng N*5000 vòng lặp thì không ổn tí nào.

Thay vì cũng 5000 vòng lặp, ta chỉ chạy 1 lần cho N bước, phải nhanh hơn nhiều chứ!
 
Upvote 0
Để em nghiên cứu hàm của anh Tuân xong em thử cải tiến tổng quát hơn. Chứ làm xong bước đầu chạy 5000 vòng lặp, lại làm bước 2, lại chạy thêm 5000 vòng lặp, nếu N bước thì chạy mất đúng N*5000 vòng lặp thì không ổn tí nào.

Thay vì cũng 5000 vòng lặp, ta chỉ chạy 1 lần cho N bước, phải nhanh hơn nhiều chứ!

Chỉ sửa hàm liên quan tới nội dung xoá phần tử thôi, đừng thêm tham số vào mà hàm bị loãng tính chuyên chuyên môn của bản thâm hàm "xoá phần tử mảng". Hàm DeleteElementArray2D để xoá phần từ mảng liên tiết từ n1-n2. Phương pháp xoá của nó không phải dùng vòng lặp đâu nhé. Đó là chuyển các byte trong bộ nhớ sang một địa chỉ khác bởi hàm rtlMoveMemory().

Ví dụ mảng có 50.000 dòng và 5 cột thì hàm DeleteElementArray2D() chỉ phải mất 5 vòng lặp để chuyển dịch các byte từ 5 cột của mảng, số vòng lặp tuỳ thuộc vào số cột của mảng, không phụ thuộc vào số dòng.

Nếu là mảng 1 chiều thì dù 100.000 dòng hay bao nhiêu đi nữa cũng không có một vòng lặp nào. Nên nếu có nhu cầu xoá nhiều dòng rời rạc thì cứ chạy lại hàm DeleteElementArray2D cho mỗi khoảng xoá sẽ không ảnh hưởng nhiều tới tốc độ đâu, nếu có thì không đáng kể.
 
Lần chỉnh sửa cuối:
Upvote 0
Chỉ sửa hàm liên quan tới nội dung xoá phần tử thôi, đừng thêm tham số vào mà hàm bị loãng tính chuyên chuyên môn của bản thâm hàm "xoá phần tử mảng". Hàm DeleteElementArray2D để xoá phần từ mảng liên tiết từ n1-n2. Phương pháp xoá của nó không phải dùng vòng lặp đâu nhé. Đó là chuyển các byte trong bộ nhớ sang một địa chỉ khác bởi hàm rtlMoveMemory().

Ví dụ mảng có 50.000 dòng và 5 cột thì hàm DeleteElementArray2D() chỉ phải mất 5 vòng lặp để chuyển dịch các byte từ 5 cột của mảng, số vòng lặp tuỳ thuộc vào số cột của mảng, không phụ thuộc vào số dòng.

Nếu là mảng 1 chiều thì dù 100.000 dòng hay bao nhiêu đi nữa cũng không có một vòng lặp nào. Nên nếu có nhu cầu xoá nhiều dòng rời rạc thì cứ chạy lại hàm DeleteElementArray2D cho mỗi khoảng xoá sẽ không ảnh hưởng nhiều tới tốc độ đâu, nếu có thì không đáng kể.

À, giờ em mới hiểu được tại sao file Anh gửi lên có tốc độ đáng nể như vậy! Cám ơn Anh.
 
Upvote 0
Chỉ sửa hàm liên quan tới nội dung xoá phần tử thôi, đừng thêm tham số vào mà hàm bị loãng tính chuyên chuyên môn của bản thâm hàm "xoá phần tử mảng". Hàm DeleteElementArray2D để xoá phần từ mảng liên tiết từ n1-n2. Phương pháp xoá của nó không phải dùng vòng lặp đâu nhé. Đó là chuyển các byte trong bộ nhớ sang một địa chỉ khác bởi hàm rtlMoveMemory().

Ví dụ mảng có 50.000 dòng và 5 cột thì hàm DeleteElementArray2D() chỉ phải mất 5 vòng lặp để chuyển dịch các byte từ 5 cột của mảng, số vòng lặp tuỳ thuộc vào số cột của mảng, không phụ thuộc vào số dòng.

Nếu là mảng 1 chiều thì dù 100.000 dòng hay bao nhiêu đi nữa cũng không có một vòng lặp nào. Nên nếu có nhu cầu xoá nhiều dòng rời rạc thì cứ chạy lại hàm DeleteElementArray2D cho mỗi khoảng xoá sẽ không ảnh hưởng nhiều tới tốc độ đâu, nếu có thì không đáng kể.

Từ đây có thể nghiên cứu thành Reszie Array không nhỉ? Tôi nghĩ món này thực tế hơn (đặc biệt là thay đổi kích thước của chiều thứ nhất)
 
Upvote 0
Từ đây có thể nghiên cứu thành Reszie Array không nhỉ? Tôi nghĩ món này thực tế hơn (đặc biệt là thay đổi kích thước của chiều thứ nhất)

Không những resize, ta có thể chèn thêm bất kỳ hàng nào vào trong mảng nữa thì tuyệt!
 
Upvote 0
Từ đây có thể nghiên cứu thành Reszie Array không nhỉ? Tôi nghĩ món này thực tế hơn (đặc biệt là thay đổi kích thước của chiều thứ nhất)

Em nghĩ là làm được. Vì một khi đã xóa được thì chèn thêm cũng cùng dạng thôi, thay đổi chút logic xử lý phần tử mảng là xong. Cái hàm DeleteElementArray2D đã fix thêm lỗi khi mảng khai báo phần tử từ 1 như là source(1 to n), lỗi thứ 2 là chạy trên Windows 64-bit thì hàm chuyển dịch byte không đúng, hiện em đang fix lỗi 64-bit, xong rồi sẽ có time để làm luôn vụ chèn dòng, chèn cột vào mảng.
 
Lần chỉnh sửa cuối:
Upvote 0
Chào Anh Tuân! sao anh lại cho hệ điều hành Win7 & office 64 bit được về hư vậy, phiềm anh thêm 1 đoạn ngắn cho hệ 64bit chạy được ko ạ

Thân

Vụ Office 64-bit mình đang tìm cách fix lỗi này. Chẳng hiểu sao cái thằng 64-bit này lỗi vớ vẫn quá.
 
Upvote 0
Em nghĩ là làm được. Vì một khi đã xóa được thì chèn thêm cũng cùng dạng thôi, thay đổi chút logic xử lý phần tử mảng là xong. Cái hàm DeleteElementArray2D đã fix thêm lỗi khi mảng khai báo phần tử từ 1 như là source(1 to n), lỗi thứ 2 là chạy trên Windows 64-bit thì hàm chuyển dịch byte không đúng, hiện em đang fix lỗi 64-bit, xong rồi sẽ có time để làm luôn vụ chèn dòng, chèn cột vào mảng.

Hè hè, vậy là chờ phiên bản 2 của Anh Tuân! Hy vọng sớm có phiên bản mới!
 
Upvote 0
Không những resize, ta có thể chèn thêm bất kỳ hàng nào vào trong mảng nữa thì tuyệt!

Nhu cầu của mình chỉ thế này là đủ:
- Đầu tiên mình Dim Arr(1 to 1000, 1 to 5) chẳng han
- Sau khi xử lý xong mảng Arr, số phần tử của chiều thứ nhất chỉ còn 500
- Khi ấy mình muốn Resize Arr(1 to 500, 1 to 5) cho vừa đủ (không thừa không thiếu)
Vậy có nghĩa là áp dụng code của Tuân, ta xóa từ 501 đến 1000 là được, đúng không?
 
Upvote 0
Nhu cầu của mình chỉ thế này là đủ:
- Đầu tiên mình Dim Arr(1 to 1000, 1 to 5) chẳng han
- Sau khi xử lý xong mảng Arr, số phần tử của chiều thứ nhất chỉ còn 500
- Khi ấy mình muốn Resize Arr(1 to 500, 1 to 5) cho vừa đủ (không thừa không thiếu)
Vậy có nghĩa là áp dụng code của Tuân, ta xóa từ 501 đến 1000 là được, đúng không?

Nhu cầu của em ngoài nhu cầu của Thầy ra em còn dùng mảng để chỉnh sửa trong mảng, ví dụ từ mảng A em lấy vài mục trong mảng đó trở thành mảng B. Nếu không có gì trục trặc thì thôi, nếu có thì xóa từ mảng B những phần tử trục trặc về lại mảng A nhưng vẫn giữ được cấu trúc ban đầu của mảng A.

Như vậy ta có thể vừa Remove mà lại vừa Insert đều được, đồng thời cũng phải nối mảng này với mảng khác được.
 
Upvote 0
Nhu cầu của mình chỉ thế này là đủ:
- Đầu tiên mình Dim Arr(1 to 1000, 1 to 5) chẳng han
- Sau khi xử lý xong mảng Arr, số phần tử của chiều thứ nhất chỉ còn 500
- Khi ấy mình muốn Resize Arr(1 to 500, 1 to 5) cho vừa đủ (không thừa không thiếu)
Vậy có nghĩa là áp dụng code của Tuân, ta xóa từ 501 đến 1000 là được, đúng không?

Vâng. Hướng giải quyết của em có thể sẽ theo như vậy. Vì tốc độ khỏi phải lo vì không phải dùng vòng lặp mà việc xóa hay chèn là xử lý byte trong bộ nhớ.
 
Upvote 0
Các hàm xử lý mảng trong bộ nhớ - Tốc độ nhanh!

Có phiên bản mới đây.

+ Hàm DeleteElementArray2D đã sửa lỗi liên quan đế khai báo phần tử thấp trong mảng. Phiên bản cũ chỉ chạy đúng nếu phần tử thấp từ 0.

+ Thêm hàm DeleteElementArray1D. Hàm này để xoá các phần tử của mảng 1 chiều.
+ Thêm hàm ConvertArray1DTo2D. Hàm này để chuyển đổi từ mảng 1 chiều sang 2 chiều. Mục đích sử dụng hàm này để điền mảng 1 chiều vào một cột trong bảng tính Excel.

Tất cả các hàm trên đều sử dụng kỹ thuật dịch chuyển các byte trong bộ nhớ, không dùng vòng lặp nên tốc độ nhanh!

(*) Lưu ý thêm:
+ Các phần tử của mảng phải là kiểu VARIANT
+ Đọc kỹ các comment trong mỗi hàm để nắm được quy tắc cũng như mục đích sử dụng hàm.
+ Download file đính kèm để chạy các thủ tục test.
+ Hiện nay tôi chạy trên Windows 6, Excel 2013 64-bit thì bị lỗi. Nhờ các bạn test trên Excel 2010 64-bit xem có lỗi không?

[GPECODE=vb]
Option Explicit
#If VBA7 Then 'Office 64-bit
Private Declare PtrSafe Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef source As Any, ByVal Length As Long)
Private Declare PtrSafe Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dst As Any, ByVal iLen&)
#Else ' Office 32-bit
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef source As Any, ByVal Length As Long)
Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dst As Any, ByVal iLen&)
#End If

Function DeleteElementArray2D(ByVal arrSource As Variant, ByVal lIndexBegin As Long, ByVal lIndexEnd As Long, Optional ByVal bEraseSource As Boolean = True) As Variant
'Programming by: Nguyen Duy Tuan - www.bluesofts.net
'arrSource: is array 2D. Elements of array with VARIANT TYPE
'Return: an array after deleting element from lIndexBegin to lIndexEnd. Elements of array with VARIANT TYPE
Dim I As Long, ilowArrayD1 As Integer, ilowArrayD2 As Integer

ilowArrayD1 = LBound(arrSource, 1)
ilowArrayD2 = LBound(arrSource, 2)

ReDim out(ilowArrayD1 To UBound(arrSource, 1) - (lIndexEnd - lIndexBegin + 1), ilowArrayD2 To UBound(arrSource, 2)) As Variant

For I = LBound(arrSource, 2) To UBound(arrSource, 2) 'Copy columns
CopyMemory ByVal VarPtr(out(ilowArrayD1, I)), ByVal VarPtr(arrSource(ilowArrayD1, I)), 16 * ((lIndexBegin - ilowArrayD1))
Next I
For I = LBound(arrSource, 2) To UBound(arrSource, 2)
CopyMemory ByVal VarPtr(out(lIndexBegin, I)), ByVal VarPtr(arrSource(lIndexEnd + 1, I)), 16 * (UBound(arrSource) - lIndexEnd)
Next I

'Return array after deleting
DeleteElementArray2D = out

If bEraseSource Then
'Erase source array in memory
For I = LBound(arrSource, 2) To UBound(arrSource, 2)
ZeroMemory ByVal VarPtr(arrSource(ilowArrayD1, I)), 16 * (UBound(arrSource) - ilowArrayD1 + 1)
Next I
Erase arrSource
End If
End Function

Function DeleteElementArray1D(ByVal arrSource As Variant, ByVal lIndexBegin As Long, ByVal lIndexEnd As Long, Optional ByVal bEraseSource As Boolean = True) As Variant
'Programming by: Nguyen Duy Tuan - www.bluesofts.net
'arrSource: is array 1D. Elements of array with VARIANT TYPE
'Return: an array 1D after deleting element from lIndexBegin to lIndexEnd. Elements of array with VARIANT TYPE
Dim I As Long, ilowArray As Integer

ilowArray = LBound(arrSource)

ReDim out(ilowArray To UBound(arrSource) - (lIndexEnd - lIndexBegin + 1)) As Variant

CopyMemory ByVal VarPtr(out(ilowArray)), ByVal VarPtr(arrSource(ilowArray)), 16 * ((lIndexBegin - ilowArray))
CopyMemory ByVal VarPtr(out(lIndexBegin)), ByVal VarPtr(arrSource(lIndexEnd + 1)), 16 * (UBound(arrSource) - lIndexEnd)

'Return array after deleting
DeleteElementArray1D = out

If bEraseSource Then
'Erase source array in memory
ZeroMemory ByVal VarPtr(arrSource(ilowArray)), 16 * (UBound(arrSource) - ilowArray + 1)
Erase arrSource
End If
End Function

Function ConvertArray1DTo2D(ByVal arrSource As Variant, Optional ByVal bEraseSource As Boolean = True) As Variant
'Programming by: Nguyen Duy Tuan - www.bluesofts.net
'arrSource: is array 1D. Elements of array with VARIANT TYPE
'Return: an array 2D. Elements of array with VARIANT TYPE
'Use this function to fill array 1D to range in 1 column
Dim I As Long, ilowArray As Integer

ilowArray = LBound(arrSource, 1)
ReDim out(ilowArray To UBound(arrSource, 1), 1 To 1) As Variant

CopyMemory ByVal VarPtr(out(ilowArray, 1)), ByVal VarPtr(arrSource(ilowArray)), 16 * (UBound(arrSource) - ilowArray + 1)

ConvertArray1DTo2D = out

If bEraseSource Then
'Erase source array in memory
ZeroMemory ByVal VarPtr(arrSource(ilowArray)), 16 * (UBound(arrSource) - ilowArray + 1)
Erase arrSource
End If
End Function
[/GPECODE]
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Có phiên bản mới đây.

+ Hàm DeleteElementArray2D đã sửa lỗi liên quan đế khai báo phần tử thấp trong mảng. Phiên bản cũ chỉ chạy đúng nếu phần tử thấp từ 0.

+ Thêm hàm DeleteElementArray1D. Hàm này để xoá các phần tử của mảng 1 chiều.
+ Thêm hàm ConvertArray1DTo2D. Hàm này để chuyển đổi từ mảng 1 chiều sang 2 chiều. Mục đích sử dụng hàm này để điền mảng 1 chiều vào một cột trong bảng tính Excel.

Tất cả các hàm trên đều sử dụng kỹ thuật dịch chuyển các byte trong bộ nhớ, không dùng vòng lặp nên tốc độ nhanh!

(*) Lưu ý thêm:
+ Các phần tử của mảng phải là kiểu VARIANT
+ Đọc kỹ các comment trong mỗi hàm để nắm được quy tắc cũng như mục đích sử dụng hàm.
+ Download file đính kèm để chạy các thủ tục test.
+ Hiện nay tôi chạy trên Windows 6, Excel 2013 64-bit thì bị lỗi. Nhờ các bạn test trên Excel 2010 64-bit xem có lỗi không?

Không biết có phải do bẫy lỗi 64-bit không, nhưng khi chạy code, máy của em nó như thế này (2 dòng màu đỏ), nhưng lại không phát sinh lỗi, vậy có sao không?
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    54.9 KB · Đọc: 109
Upvote 0
Không biết có phải do bẫy lỗi 64-bit không, nhưng khi chạy code, máy của em nó như thế này (2 dòng màu đỏ), nhưng lại không phát sinh lỗi, vậy có sao không?

Cái màu đỏ là khai báo hàm sử dụng trong Office 64-bit, do a Nghĩa chạy trong 32-bit thì phần khai bó đó không sử dụng, còn nếu chạy trong Office 64-bit thì khi màu đỏ đó lại được trình biên dịch kiểm tra và không bị đỏ, phần 32-bit sẽ chuyển thành màu đỏ. Tóm lại hiện tượng trên không phải là lỗi. Lỗi phải xảy ra khi chạy code, mảng trả về có đúng số phần tử và đúng giá trị hay không.
 
Upvote 0
Cái màu đỏ là khai báo hàm sử dụng trong Office 64-bit, do a Nghĩa chạy trong 32-bit thì phần khai bó đó không sử dụng, còn nếu chạy trong Office 64-bit thì khi màu đỏ đó lại được trình biên dịch kiểm tra và không bị đỏ, phần 32-bit sẽ chuyển thành màu đỏ. Tóm lại hiện tượng trên không phải là lỗi. Lỗi phải xảy ra khi chạy code, mảng trả về có đúng số phần tử và đúng giá trị hay không.

testArray1D thì chạy tốt, nhưng ở giữa Item1 và 10 có 1 ô trống
còn khi chạy TestArray2D thi bị out office (em xài office 2010 64 bit ) trên máy của em lỗi là vậy
 
Upvote 0
testArray1D thì chạy tốt, nhưng ở giữa Item1 và 10 có 1 ô trống
còn khi chạy TestArray2D thi bị out office (em xài office 2010 64 bit ) trên máy của em lỗi là vậy

Vụ này hàm dịch chuyển byte nó lại bị sai trong Windows 64-bit, mình đang tìm cách mà cũng thấy khó quá.
 
Upvote 0
Vụ này hàm dịch chuyển byte nó lại bị sai trong Windows 64-bit, mình đang tìm cách mà cũng thấy khó quá.

Nếu không xóa mảng cũ, tức có

Mã:
Sub TestArray2D()
    ...    
    dest = DeleteElementArray2D(source, 3, 6, [COLOR=#ff0000]False[/COLOR])
    
    ...
End Sub

thì khi ra khỏi DeleteElementArray2D bị out (XP Home + Excel 2007)
 
Upvote 0
Upvote 0

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

Back
Top Bottom