Load và lấy số liệu từ biến người dùng xuống Sheet không dùng vòng lặp? (1 người xem)

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

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

sealand

Thành viên gạo cội
Tham gia
16/5/08
Bài viết
4,883
Được thích
7,688
Giới tính
Nam
Nghề nghiệp
Kế Toán
Trong VBA ta phải công nhận sử lý dữ liệu trên mảng cho tốc độ nhanh hơn nhiều lần sử lý trên bảng tính. Nhưng hạn chế của mảng là các chỉ số không gợi ý cho việc viết và kiểm tra câu lệnh. Mình muốn dùng biến người dùng tự tạo thay thế nhưng chưa tìm được cách load và lấy dữ liệu không dùng vòng lặp như Array.
Để dễ hiểu, mình ví dụ:

Trên Sheet có 3 cột Họ tên-Tuổi-CMND
Giờ mình khai báo và load dữ liệu dùng vòng lặp:
PHP:
'Khai báo 1 biến người dùng tự định nghĩa có tên Lylich

Public Type Lylich
 Hoten as String*20
 Tuoi as Integer
 CMND as String*10
End Type


Sub LoadDT()
Dim i as Integer
Dim HSo(10) as Lylich
'Load dữ liệu từ Sheet lên biến

For i=1 to 10
With HSo(i)
.Hoten=sheet1.Cells(i,1)
.Tuoi=sheet1.Cells(i,2)
.CMND=sheet1.Cells(i,3)
End with
Next i

'Lấy dữ liệu
With HSo(5)
Msgbox .Hoten & "-" & .Tuoi & "-" & .CMND
End sub

Như vậy ta có thể dùng biến này như 1 mảng thông thường với các chỉ số rất gợi ý.
Nhưng chết nỗi mình chưa làm được thắc mắc ở phần trên. Ai biết xin hướng dẫn giùm.
Xin cám ơn nhiều.
 
Trong VBA ta phải công nhận sử lý dữ liệu trên mảng cho tốc độ nhanh hơn nhiều lần sử lý trên bảng tính. Nhưng hạn chế của mảng là các chỉ số không gợi ý cho việc viết và kiểm tra câu lệnh. Mình muốn dùng biến người dùng tự tạo thay thế nhưng chưa tìm được cách load và lấy dữ liệu không dùng vòng lặp như Array.
Để dễ hiểu, mình ví dụ:

Trên Sheet có 3 cột Họ tên-Tuổi-CMND
Giờ mình khai báo và load dữ liệu dùng vòng lặp:
PHP:
'Khai báo 1 biến người dùng tự định nghĩa có tên Lylich

Public Type Lylich
 Hoten as String*20
 Tuoi as Integer
 CMND as String*10
End Type


Sub LoadDT()
Dim i as Integer
Dim HSo(10) as Lylich
'Load dữ liệu từ Sheet lên biến

For i=1 to 10
With HSo(i)
.Hoten=sheet1.Cells(i,1)
.Tuoi=sheet1.Cells(i,2)
.CMND=sheet1.Cells(i,3)
End with
Next i

'Lấy dữ liệu
With HSo(5)
Msgbox .Hoten & "-" & .Tuoi & "-" & .CMND
End sub

Như vậy ta có thể dùng biến này như 1 mảng thông thường với các chỉ số rất gợi ý.
Nhưng chết nỗi mình chưa làm được thắc mắc ở phần trên. Ai biết xin hướng dẫn giùm.
Xin cám ơn nhiều.

Nếu em hiểu ý của anh, thì hình như giống bài đố vui VBA, với đáp án là bài #686, tại đây: http://www.giaiphapexcel.com/forum/showthread.php?7146-%C4%90%E1%BB%91-vui-v%E1%BB%81-VBA%21&p=494606#post494606
 
Upvote 0
Upvote 0
Có thể sửa code bài #4 lại cho gọn (nhưng chưa chắc đã hay), như sau:
Bỏ bớt một Class và một hàm.
Mình nghĩ đây là đề tài hay. Mời các cao thủ đóng góp để hoàn chỉnh thêm, vì sức mình chỉ tới đó, số Class làm được có thể đếm bằng ngón tay, hi hi.
 

File đính kèm

Upvote 0
Mình nghĩ đây là đề tài hay. Mời các cao thủ đóng góp để hoàn chỉnh thêm, vì sức mình chỉ tới đó, số Class làm được có thể đếm bằng ngón tay, hi hi.

Khi tiếp cận với Class, trước giờ em chưa từng dùng đến Property Let, Get, Set... Vì:
- Không có nhu cầu
- Em không cảm thấy đó là giải pháp duy nhất (giải pháp duy nhất nghĩa là nếu không có nó thì không được)
- Theo như anh siwtom có lần phân tích thì mấy trò Property Let, Get, Set.. có thể khiến code trở thành trường phái X mà thôi
----------------
Với class em chỉ hứng thú với mấy trò tạo sự kiện người dùng (vì thiếu nó thì có khi code sẽ rất dài, thậm chí là không thể viết được)
 
Lần chỉnh sửa cuối:
Upvote 0
Khi tiếp cận với Class, trước giờ em chưa từng dùng đến Property Let, Get, Set... Vì:
- Không có nhu cầu
- Em không cảm thấy đó là giải pháp duy nhất (giải pháp duy nhất nghĩa là nếu không có nó thì không được)
- Theo như anh siwtom có lần phân tích thì mấy trò Property Let, Get, Set.. có thể khiến code trở thành trường phái X mà thôi
----------------
Với class em chỉ hứng thú với mấy trò tạo sự kiện người dùng (vì thiếu nó thì có khi code sẽ rất dài, thậm chí là không thể viết được)

Nhưng với yêu cầu của anh sealand thì có giải pháp gì thay cho Class?
Vì dụ:
Thay Msgbox ArrNguoi(i, 2)
Thành Msgbox Nguoi(i).Tuoi
Nhưng khi Gán range vào mảng, mảng vào range không được dùng vòng lặp


 
Lần chỉnh sửa cuối:
Upvote 0
Nhưng với yêu cầu của anh sealand thì có giải pháp gì thay cho Class?
Vì dụ:
Thay Msgbox ArrNguoi(i, 2)
Thành Msgbox Nguoi(i).Tuoi

Thì em dùng Array cũng được vậy!
Ý em muốn nói rằng cái giải pháp Class ấy không phải là duy nhất (đến mức không có thì không được)
Ví dụ: Em dùng array và cần thông qua 1 vòng lập, trong khi anh dùng class lại không cần đến vòng lập nào ---> Khi ấy em mới phục thằng Class (giống như đã phục thằng VBScript.RegExp vậy)
Bài này cùng lắm anh chỉ "gắn" thêm cho nó mấy cái Properties để trực quan thôi (và code trở nên bí hiểm theo trường phái X)
Ẹc.. Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Thì em dùng Array cũng được vậy!
Ý em muốn nói rằng cái giải pháp Class ấy không phải là duy nhất (đến mức không có thì không được)
Ví dụ: Em dùng array và cần thông qua 1 vòng lập, trong khi anh dùng class lại không cần đến vòng lập nào ---> Khi ấy em mới phục thằng Class (giống như đã phục thằng VBScript.RegExp vậy)
Bài này cùng lắm anh chỉ "gắn" thêm cho nó mấy cái Properties để trực quan thôi (và code trở nên bí hiểm theo trường phái X)
Ẹc.. Ẹc...

Thực ra "không dùng vòng lặp" chỉ là được giấu kín thôi.
Nếu tôi làm như sau:
Mã:
đập dữ liệu từ sheet vào Arr
[B][COLOR=#ff0000]trong vòng FOR nhập từ Arr vào các LyLich[/COLOR][/B]
...
tính toán với các dữ liệu của từng LyLich
...
Trong vòng FOR nhập từ các LyLich vào Arr
đập Arr xuống Sheet

Theo các bạn như thế là dùng vòng lặp?

Thế cái
Mã:
    Nguoi.Hoten = StrDS(Index, 1)
    Nguoi.Tuoi = StrDS(Index, 2)
    Nguoi.CMND = StrDS(Index, 3)

nó là cái gì? Nó là cái tương ứng với cái tôi tô đỏ ở trên. Đằng nào cũng phải đọc UBound(Arr) - LBound(Arr) + 1 lần dữ liệu từ Arr vào LyLich để tính toán. Thường các tính toán nằm trong vòng lặp nên code trên (Nguoi) cũng chả nằm trong vòng lặp là gì?
 
Upvote 0
Thực ra "không dùng vòng lặp" chỉ là được giấu kín thôi.
Nếu tôi làm như sau:
Mã:
đập dữ liệu từ sheet vào Arr
[B][COLOR=#ff0000]trong vòng FOR nhập từ Arr vào các LyLich[/COLOR][/B]
...
tính toán với các dữ liệu của từng LyLich
...
Trong vòng FOR nhập từ các LyLich vào Arr
đập Arr xuống Sheet

Theo các bạn như thế là dùng vòng lặp?

Thế cái
Mã:
    Nguoi.Hoten = StrDS(Index, 1)
    Nguoi.Tuoi = StrDS(Index, 2)
    Nguoi.CMND = StrDS(Index, 3)

nó là cái gì? Nó là cái tương ứng với cái tôi tô đỏ ở trên. Đằng nào cũng phải đọc UBound(Arr) - LBound(Arr) + 1 lần dữ liệu từ Arr vào LyLich để tính toán. Thường các tính toán nằm trong vòng lặp nên code trên (Nguoi) cũng chả nằm trong vòng lặp là gì?

Ha ha bắt được anh rồi, anh xem viết thêm cho em cái vụ set, let gì đó để gán giá grị vào biến. Hiện tại biến của em mới chỉ đọc thôi.
Ví dụ em muốn gán (Edit mảng): Nguoi(1).Name = "Nguyễn Văn A" thì chưa được.
Đồng ý là có vòng lặp nhưng chỉ là lặp theo một chiều ngắn (chiều cột)
Em đang chập chững viết Class mà, rất cảm ơn anh đã góp ý!
 
Upvote 0
Các anh cho giải thích cụ thể 1 chút đã:
-Mảng: Tốc độ nhanh. Nhưng hạn chế về trực quan khi viết và quản lý code liên quan.
-Biến người dùng: Gợi ý trực quan tốt và nó cũng giống mảng, nhưng chưa biết sử dụng.

Vậy thì với dân GPE (vì Exc mới có) load 1 mảng lên 1 array không nhất thiết phải load lần lượt mà chỉ cần lệnh gán là xong. Ví dụ

Mã:
Sub Th()
Dim MyArr()
MyArr = Sheet1.[A1:C10].Value
MsgBox UBound(MyArr, 1) & "-" & UBound(MyArr, 2)
End Sub

Vậy có cách nào gán cho biến khai báo bằng Type như ví dụ trên không?
 
Upvote 0
Các anh cho giải thích cụ thể 1 chút đã:
-Mảng: Tốc độ nhanh. Nhưng hạn chế về trực quan khi viết và quản lý code liên quan.
-Biến người dùng: Gợi ý trực quan tốt và nó cũng giống mảng, nhưng chưa biết sử dụng.

Vậy thì với dân GPE (vì Exc mới có) load 1 mảng lên 1 array không nhất thiết phải load lần lượt mà chỉ cần lệnh gán là xong. Ví dụ

Mã:
Sub Th()
Dim MyArr()
MyArr = Sheet1.[A1:C10].Value
MsgBox UBound(MyArr, 1) & "-" & UBound(MyArr, 2)
End Sub

Vậy có cách nào gán cho biến khai báo bằng Type như ví dụ trên không?

Tôi nghĩ bạn cứ "đập" từ sheet vào Arr rồi trong vòng lặp nhập vào LyLich. Trong vòng lặp nhập từ sheet vào LyLich thì lâu chứ nhập từ Arr chắc hẳn nhanh. Tôi nghĩ chắc chả có cách nhanh hơn đâu.
 
Upvote 0
Đồng ý là có vòng lặp nhưng chỉ là lặp theo một chiều ngắn (chiều cột)

Bạn chưa hiểu ý tôi.
Khi ta làm việc với mảng thì thường là ta đi hết tất cả các dòng - đi trong vòng lặp - và xử lý mỗi dòng đó.
Như vậy nếu mảng có n dòng thì bạn phải "đọc ra" n lần LyLich. Tất nhiên mỗi khi đọc ra một LyLich thì bạn "đi theo cột" nhưng tổng cộng bạn vẫn có n lần đọc ra n LyLich.

Ha ha bắt được anh rồi, anh xem viết thêm cho em cái vụ set, let gì đó để gán giá grị vào biến. Hiện tại biến của em mới chỉ đọc thôi.
Ví dụ em muốn gán (Edit mảng): Nguoi(1).Name = "Nguyễn Văn A" thì chưa được.

Em đang chập chững viết Class mà, rất cảm ơn anh đã góp ý!

Tôi ngại làm quá.
Nhưng nếu bạn chỉ muốn bổ sung vào code đã có sẵn thì thế này:
1. Bạn phải dùng Property Let. Set ta dùng với những type đơn giản thôi: numeric, boolean, string v...v Với Object, struct - TYPE thì dùng Let.

2. code

Module1
Mã:
Option Explicit

Public Type Lylich
    Hoten As String
    Tuoi As Integer
    CMND As String
End Type

Sub Test()
    Dim MyCty As ClassArray
    Dim i As Integer, ll As Lylich
    Dim Arr()

    Arr = Sheet1.Range("B2:D5")

    Set MyCty = New ClassArray
    MyCty.LoadDS Arr

    MsgBox MyCty.Count & " nguoi"
    
    ll.Hoten = "Nguyen Van B"
    ll.Tuoi = 45
    ll.CMND = "AJG19677"
    
    MyCty.Nguoi(2) = ll
    
    For i = 1 To MyCty.Count
        MsgBox MyCty.Nguoi(i).Hoten & "/" & MyCty.Nguoi(i).Tuoi & "/" & MyCty.Nguoi(i).CMND
    Next
    Sheet1.Range("K2:M5") = MyCty.GetDS
End Sub

ClassArray
Mã:
Option Explicit

Private FArrDS As Variant
Private FCount As Long

Public Property Get Nguoi(ByVal index As Integer) As Lylich
    If (0 < index) And (index <= FCount) Then
        Nguoi.Hoten = FArrDS(index, 1)
        Nguoi.Tuoi = FArrDS(index, 2)
        Nguoi.CMND = FArrDS(index, 3)
    End If
End Property

Public Property Let Nguoi(ByVal index As Integer, DS As Lylich)
    If (0 < index) And (index <= FCount) Then
        FArrDS(index, 1) = DS.Hoten
        FArrDS(index, 2) = DS.Tuoi
        FArrDS(index, 3) = DS.CMND
    End If
End Property

Public Property Get Count() As Integer
    Count = FCount
End Property

Public Property Get GetDS()
    GetDS = FArrDS
End Property

Public Sub LoadDS(ArrDS() As Variant)
    FArrDS = ArrDS
    FCount = UBound(FArrDS) - LBound(FArrDS) + 1
End Sub

-----------

Chỉ để tham khảo thôi
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn anh siwtom nhiều, em cứ loay hoay với thủ tục Public Property Let Nguoi(ByVal index As Integer, DS As Lylich). Ngoài ra các (biến) thuộc tính đã được anh chuyển thành Private nên bài bản hơn, "kỷ luật" hơn (chính hiệu là trường phái X).
He he em được một món ăn ngon nữa rồi.

Với em đây là một Class khó (vì sử lý mảng), nếu không thích ứng dụng thì cũng là một bài học hay về Class.
Một lần nũa cảm ơn anh đã sửa chữa và bổ sung.
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom