Đố vui về VBA!

Liên hệ QC

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,905
Nhằm cũng cố kiến thức về VBA cho các bạn mới bắt đầu và cả những bạn đang ứng dụng mà chưa hiểu nhiều về nó, tôi mở topic này với mong mõi qua những câu hỏi vui, các bạn sẽ nhận định lại sự hiểu biết cũa mình... (Kễ cã chính tôi cũng đang tập tành nên có rất nhiều cái chưa biết)
Mong rằng topic sẽ mang đến cho các bạn những khám phá thú vị với những cái tưỡng chừng như đã biết
Mong nhận dc bài viết về câu đố cũa các cao thủ! Còn các bạn mới thì đừng ngại khi đưa ra ý kiến cũa mình.. Có sai có sữa sẽ hoàn thiện!
Tôi xin mỡ màn trước bằng 1 câu hỏi đơn giãn
ANH TUẤN

CÂU HỎI 1: Tại sao biến K ko hoạt động?
Tôi muốn khi nhấn vào 1 button thì cell A1 sẽ tăng lên 1 đơn vị... Tôi đã làm như sau:
-Tạo 1 Command Button (nút nhấn thuộc thanh Control Toolbox), click phải chuột lên nút nhấn, chọn View code, rồi gõ vào đoạn code sau:
PHP:
Private Sub CommandButton1_Click()
   K = K + 1
   Range("A1").Value = K
End Sub
Ban đầu K chưa có gì, xem như =0, nhấn nút lần thứ nhất thì K dc tăng thêm 1, vậy K hiện tại sẽ bằng 1, và gán K vào cell A1 thì đương nhiên A1 sẽ =1... Nhấn nút lần 2, K lại dc tăng thêm 1 nên hiện tại K sẽ =2 và cell A1 cũng sẽ =2... vân vân.. từ đó diễn tiến tiếp...
Hi.. hi.. Điều này nghe qua có vẽ rất hợp lý, ấy thế mà khi nhấn nút nó chỉ hoạt động dc duy nhất 1 lần (A1 = 1) rồi thôi ko nhút nhít nữa...
Các bạn có thể giãi thích tại sao lại như thế ko? Tại sao những lần nhấn nút sau đó K lại ko tăng thêm tí nào (vì thực tế A1 vẫn cứ = 1 hoài) ?
ANH TUẤN
 
Âu cũng đặng, ví như cơ cấu giải thưởng có nhất, nhì, ba , khuyến khích và trên tất thảy lại là giải đặc biệt đó thôi.
_)(#;
Chỉ có xổ số Việt Nam sau nầy mới dùng "giải đặc biệt" là giải lớn nhất, thông thường giải đặc biệt là giải phụ và giá trị thấp hơn giải nhất nhiều
 
Upvote 0
Đố mẹo, chỉ thử độ hiểu biết VBA. Nếu bạn không cho đấy là thục dụng thì cứ coi như câu đố không liên quan gì đến thực dụng.

Có một array được khai báo như vầy:
Public mang(1 to 10)

Bây giờ làm cách nào nạp 1..10 vào 10 phần tử của mảng?

Điều kiện buộc:
Không dùng vòng lặp. Không dùng lệnh GoTo theo kiểu vòng đi vòng lại (vòng lặp tự tạo). Vầ ai cũng biết đệ quy có thể thay thế 99% trường hợp vòng lặp cho nên cũng không được dùng luôn.
Đương nhiên kiểu 10 lệnh code mang(1) = 1: mang2) = 2 :... là không được.

Điều kiện mở:
Không cần code tối ưu hay tối u gì cả. Miễn ra kết quả thôi.
Có quyền làm việc tùm lum. Muốn để lại một đống rác cũng chả ai trách. Miễn có kết quả thôi.
.
 
Lần chỉnh sửa cuối:
Upvote 0
Đố mẹo, chỉ thử độ hiểu biết VBA. Nếu bạn không cho đấy là thục dụng thì cứ coi như câu đố không liên quan gì đến thực dụng.

Có một array được khai báo như vầy:
Public mang(1 to 10)

Bây giờ làm cách nào nạp 1..10 vào 10 phần tử của mảng?

Điều kiện buộc:
Không dùng vòng lặp. Không dùng lệnh GoTo theo kiểu vòng đi vòng lại (vòng lặp tự tạo). Vầ ai cũng biết đệ quy có thể thay thế 99% trường hợp vòng lặp cho nên cũng không được dùng luôn.
Đương nhiên kiểu 10 lệnh code mang(1) = 1: mang2) = 2 :... là không được.

Điều kiện mở:
Không cần code tối ưu hay tối u gì cả. Miễn ra kết quả thôi.
Có quyền làm việc tùm lum. Muốn để lại một đống rác cũng chả ai trách. Miễn có kết quả thôi.
.
Tưởng gì bác, em khơi mào đống rác thứ 1.
Sau khi thử đi thử lại (thêm ngoặc, bỏ ngoặc, thêm phần tử, bỏ phần tử, thêm set, bỏ set, thêm redim, bỏ redim, ...) khoảng vài chục lần là nó ra.
Nhưng em không hiểu tại sao nó ra nhé.
Mã:
Public mang(1 To 10)
Sub jkl()
Dim mang()
Range("a1:a10").Value = Application.WorksheetFunction.Sequence(10)
mang() = Range("a1:a10").Value
Range("b1:b10").Value = mang()
End Sub
 
Upvote 0
Tưởng gì bác, em khơi mào đống rác thứ 1.
Sau khi thử đi thử lại (thêm ngoặc, bỏ ngoặc, thêm phần tử, bỏ phần tử, thêm set, bỏ set, thêm redim, bỏ redim, ...) khoảng vài chục lần là nó ra.
Nhưng em không hiểu tại sao nó ra nhé.
...
Khơi trật đống rác rồi. Có thấy cái gì nhét vào mang đâu mà bảo là ra:

1674754945139.png

Chấm điểm: một con nhạn bị tên.

Gợi ý: tôi đã bảo là thử độ hiểu biết. Nên tìm hiểu về biến và tầm vực của biến.
Tự tìm lấy. Nếu tôi tự dẫn bài của mình thì hóa ra là tự sướng?
 
Upvote 0
Khơi trật đống rác rồi. Có thấy cái gì nhét vào mang đâu mà bảo là ra:

View attachment 285900

Chấm điểm: một con nhạn bị tên.

Gợi ý: tôi đã bảo là thử độ hiểu biết. Nên tìm hiểu về biến và tầm vực của biến.
Tự tìm lấy. Nếu tôi tự dẫn bài của mình thì hóa ra là tự sướng?
À, mang () em cho vào B1:B10 rồi. Xong sub thì mang() về rỗng mà.
Mà mang() khi dim chắc cũng không đúng nữa, hình như nó thành mang(0 to 9) thì phải.
Sequence lại máy có máy không nữa.
Còn ý là thêm yêu cầu khác đấy, xong sub biến phải còn sống. Thế thì khó đây.

PS: bài biến của bác em xem rồi, khiếp toàn chữ là chữ. Tính em thì thích đọc truyện tranh, hình ảnh mới dễ nhớ được.
 
Upvote 0
À, mang () em cho vào B1:B10 rồi. Xong sub thì mang() về rỗng mà.
Mà mang() khi dim chắc cũng không đúng nữa, hình như nó thành mang(0 to 9) thì phải.
Sequence lại máy có máy không nữa.
Còn ý là thêm yêu cầu khác đấy, xong sub biến phải còn sống. Thế thì khó đây.

PS: bài biến của bác em xem rồi, khiếp toàn chữ là chữ. Tính em thì thích đọc truyện tranh, hình ảnh mới dễ nhớ được.
Xin lỗi trước, tôi không có ý chê hay chỉ trích cá nhân bạn.

Bạn lười đọc chữ cho nên biết các thủ thuật hạng trung (trên bắt đầu) nhưng khong có căn bản từ đầu.
Điển hình, trong code bạn dùng kỹ thuât copy range ra mảng và copy ngược lại là kỹ thuật của bậc trung. Nhưng về vấn dề cái mảng của bạn là gì thì bạn hoàn toàn không biết.

Đề bài tôi đưa ra một chiếc xe, nhờ đổ xăng cho đầy.
Bạn chỉ cho tôi thấy bạn có đổ xăng nhưng khi tôi xem lại thì xe tôi chả có giọt xăng nào.
Gợi ý: nếu bạn hiểu căn bản về biến thì đã biết bạn đổ xăng vào xe nhà của bạn. Trong suốt quá trình bạn làm việc, bạn không hề cầm đến chìa khóa xe tôi. Chưa chắc bạn đã biết nó màu xanh hay đỏ, đừng nói đến đổ xăng.
 
Upvote 0
Khơi trật đống rác rồi.
Tôi bỏ câu Dim mang(), chạy code sairoi của anh, chạy trực tiếp code của cantl, đều bị lỗi can't assign to array, nếu chỉ khai báo Public mang() không kích thước thì được. Anh cho biết vì sao? Xin cám ơn.
 
Upvote 0
Tôi bỏ câu Dim mang(), chạy code sairoi của anh, chạy trực tiếp code của cantl, đều bị lỗi can't assign to array, nếu chỉ khai báo Public mang() không kích thước thì được. Anh cho biết vì sao? Xin cám ơn.
Mảng có hai loại, fixed length và dynanic.
Mảng tôi ra trong đề bài là fixed length. Tuy chưa định kiểu (các phần tửu hiện tại là variant)
Cái phương thức của range cho phép chopy range ra mảng cho ra mảng động. Vì vậy phải bào mang() thì được.

Nhng dề bài tôi cố tình dùng mảng tĩnh để buoojc quý vị có muốn chơi copy từ reaneg thì cũng vất vả chút, chứ dễ vậy thì đố mần chi.
 
Upvote 0
Cái phương thức của range cho phép copy range ra mảng cho ra mảng động. Vì vậy phải bào mang() thì được.
Tôi bỏ phương thức copy range vì copy range cho ra mảng 2 chiều, trong khi khai báo của anh là 1 chiều. Dùng cách khác như mang = array(...), hoặc bằng evaluate("...") cũng bị lỗi can't assign. Và đã tự rút ra kết luận.
Câu tôi hỏi là theo hình anh chụp thì chạy được mà không bị lỗi?
 
Lần chỉnh sửa cuối:
Upvote 0
Đố mẹo, chỉ thử độ hiểu biết VBA. Nếu bạn không cho đấy là thục dụng thì cứ coi như câu đố không liên quan gì đến thực dụng.

Có một array được khai báo như vầy:
Public mang(1 to 10)

Bây giờ làm cách nào nạp 1..10 vào 10 phần tử của mảng?

Điều kiện buộc:
Không dùng vòng lặp. Không dùng lệnh GoTo theo kiểu vòng đi vòng lại (vòng lặp tự tạo). Vầ ai cũng biết đệ quy có thể thay thế 99% trường hợp vòng lặp cho nên cũng không được dùng luôn.
Đương nhiên kiểu 10 lệnh code mang(1) = 1: mang2) = 2 :... là không được.

Điều kiện mở:
Không cần code tối ưu hay tối u gì cả. Miễn ra kết quả thôi.
Có quyền làm việc tùm lum. Muốn để lại một đống rác cũng chả ai trách. Miễn có kết quả thôi.
.
Em chưa mở máy được để thử, không biết transpose kết hợp evaluate có giải quyết được câu này không
 
Upvote 0
...
Câu tôi hỏi là theo hình anh chụp thì chạy được mà không bị lỗi?
Hình chụp ở bài #1444 là tôi chứng minh cho tác giả bài #1443 rằng sau khi chạy sub jkl (giải pháp của tác giả), mảng vẫn trống trơn.
Bài kế có giải thích cho tác giả rằng tôi tin xăng có đổ (biên lai rõ ràng), nhưng xe nào đó chứ chẳng phải xe tôi nhờ đổ (có thấy ai đến lấy chìa khóa xe đâu).. Tức là code chạy không lỗi gì cả, nhưng code ấy chả ăn nhập gì đến mảng của tôi.
 
Lần chỉnh sửa cuối:
Upvote 0
Hình chụp ở bài #1444 là tôi chứng minh cho tác giả bài #1443 rằng sau khi chạy sub jkl (giải pháp của tác giả), mảng vẫn trống trơn.
Tôi nhìn thấy sự trống trơn, và biết nguyên nhân trống trơn rồi. Nhưng anh chạy cách nào ra thông báo trống trơn đó mà không bị lỗi can't assign?
 
Upvote 0
Tôi nhìn thấy sự trống trơn, và biết nguyên nhân trống trơn rồi. Nhưng anh chạy cách nào ra thông báo trống trơn đó mà không bị lỗi can't assign?
Dòng Public mang(1 To 10) là kiểu xác định khá rõ, chỉ còn thiếu As Long nữa là 100%.
Tuy không thể phát luôn 40 bytes cho mang nhưng cũng đủ để trình dịch phát bộ nhớ cho 10 variant.
Vì vậy, khi code sub sairoi truy cập phần tử mang(5) thì chả có vấn đề gì.
Nếu mang được khai báo là mảng động thì trình dịch chỉ để tên đó nhưng không cấp phát bộ nhớ (kết nối trễ). Luc ấy code truy cập sẽ bị lỗi. Tôi đã từng viết bài chỉ dẫn cách thủ mảng đã có địa chỉ chưa, chịu khó tìm.

Lưu ý:
Nếu mảng của tôi được khai báp là
Public mang(1 To 10) As Long
thì trình dịch sẽ cấp phát luôn một dãy 40 bytes cho biến mang; đồng thơi, VBA cũng sẽ khởi trị mặc định cho cacs phần tử là 0.
Lúc tôi chạy sub sairoi sẽ thấy msgbox trưng ra 0 chứ không phải trống trưn.
 
Lần chỉnh sửa cuối:
Upvote 0
Đố mẹo, chỉ thử độ hiểu biết VBA. Nếu bạn không cho đấy là thục dụng thì cứ coi như câu đố không liên quan gì đến thực dụng.

Có một array được khai báo như vầy:
Public mang(1 to 10)

Bây giờ làm cách nào nạp 1..10 vào 10 phần tử của mảng?

Điều kiện buộc:
Không dùng vòng lặp. Không dùng lệnh GoTo theo kiểu vòng đi vòng lại (vòng lặp tự tạo). Vầ ai cũng biết đệ quy có thể thay thế 99% trường hợp vòng lặp cho nên cũng không được dùng luôn.
Đương nhiên kiểu 10 lệnh code mang(1) = 1: mang2) = 2 :... là không được.

Điều kiện mở:
Không cần code tối ưu hay tối u gì cả. Miễn ra kết quả thôi.
Có quyền làm việc tùm lum. Muốn để lại một đống rác cũng chả ai trách. Miễn có kết quả thôi.
.
Có thể dùng hàm API CopyMemory là một giải pháp.
 
Upvote 0
Có thể dùng hàm API CopyMemory là một giải pháp.
Đúng là một giải pháp.
Cũng như đệ quy giải được hết 99% vòng lạp, dùng pointer để copy memory là một thủ thuât để chuyển trị từ mảng này sang mảng khác.

Có ai ra giải pháp gì nữa không?
(ở trên tôi cố ý khơi "đệ quy" để gợi ý cách giải của tôi - không đệ quy nhưng cũng gần như vậy)
 
Upvote 0
Dùng sự kiện change của worksheet để tạo vòng lặp được tính không anh?
Đó là cách của tôi.
Bài này vốn chôm từ câu đố bất hủ của LTHĐT.
Với C++, người ta tạo một lớp (lớp A) chứa một mảng 10 đối tượng của lớp khác (lớp B).
Trong hàm dựng của lớp B, có code dựa vào vị trí của đối tuonwgj này mà ghi trị vào vị trí tương ứng trên mảng yêu cầu.
Khi tạo đối tượng (instantiate) lớp A, hàm dựng của A sẽ tự động tạo các đối tượng lớp B; và hàm dựng của B sẽ tự dộng làm việc, đủ 10 lần cho 10 đối tượng.
Tuy cấu này vốn đố trên C++ nhưng tôi tin rằng tất cả các ngôn ngữ LTHĐT đều có cách làm tương tự. Bạn có thể thử Python xem.

Rất tiếc VBA khong phải là ngôn ngữ hướng đối tượng. Class Module của VBA khong có hàm nào được tự động gọi khi đối tượng được khởi tạo.
Vì vậy, nguyên tắc trong giải pháp của tôi là phải dựa vào một cái gfi để buộc VBA tự động chạy code ghi trị vào mảng. Chỗ dễ thấy nhất là bắt sự kiện.
Tôi chỉ nói dễ thấy, có thể còn nhiều cách đào sâu hơn mọt chút thì thấy.
Và cách của bài #1454 rõ ràng là không cần chạy tự động cái gì cả.

Mặt khác:.
Có ai còn cách khác? Ở đây không ai nói đến chuyện cách nào hay hơn cách nào. Những phương pháp tư duy khác nhau mới là quan trọng.
 
Upvote 0
Năm nay chắ quý vị Thầy/Cô ăn Tết lơn, quên ra bài tập. Chứ theo mọi năm thì mùa này tràn ngập học sinh hỏi hoặc nhờ làm giúm bài tập.

Thôi thì trong lúc bà con ngóng mỏ, đố tiếp. Câu này dễ thôi - chỉ dùng ôn lại kiến thức.

Code (có lẽ ngắn nhất) cho một hàm tính giai thừa (n!) là:

Function giaithua(n)
If n <= 1 Then giaithua = 1 Else giaithua = n * giaithua(n - 1)
End Function

Nếu tôi muốn ngắn hơn thì dùng hàm IIF:

Function giaithua(n)
giaithua =IIF( n <= 1, 1, n * giaithua(n - 1)
End Function

Có đúng không? Xin quý vị phân tích.

Bố-nợt cho các bạn chuyên Google Sheets và G Script
Bài này viết G Script ra sao?
 
Upvote 0
Web KT
Back
Top Bottom