Viết hàm như thế nào là tốt

  • Thread starter Tuanktcdcn
  • Ngày gửi
T

Tuanktcdcn

Lão già ham vui
18/6/04
549
52
28
48
Hà Nội
www.bluesofts.net
Chúng ta biết tại sao chỉ có mấy hàm của Excel mà chúng ta mỗi người mỗi nghề có thể dùng nó để giải quyết công việc. Các hàm được xây dựng phải giải quyết theo hướng tổng quát không nên cụ thể một chi tiết trừ khi bắt buộc. Người dùng Excel có thể vận dụng hàm để sáng tác ra các công thức khác nhau, sự thông minh (công thức ngắn gọn+tốc độ xửa lý nhanh+dễ nhớ...) của nó tùy vào sáng tạo và tư duy của mỗi người. Đây chính là điểm mạnh của Excel và làm cho chúng ta cứ như mắc nợ Excel!

Chắc hẳn chúng ta ai cũng muốn mình học VBA để biết tạo ra các hàm không những cho mình và cả những người khác sử dụng! Vậy chúng nên thiết kế hàm như thế nào là tốt nhất? Để giải quyết câu hỏi này chúng ta bắt đầu từng việc:


1-Khai báo và đặt tên Thủ tục, Hàm, Biến, Hằng (Sub, Function, Dim, Const)


Bàn vào việc đặt tên mỗi người nên chọn một kiểu gọi là "chuẩn", có thể bằng tiếng Anh hay Việt. Theo tôi các bạn nên đặt theo tiếng Anh vì ngắn gọn hơn.

Việc đặt tên thực sự rất quan trọng (chúng ta trân trọng như là đặt tên cho con mình). Các bạn hình dung thế này, nếu chúng ta có hàng trăm phương tiện, công cụ làm việc, khi cần một việc gì đó chúng ta cần gọi nó ra ngay thì liệu chúng ta có nhớ tên gọi của nó không? Phương pháp đặt tên để giúp ta dễ nhớ hơn.

+ Tên Thủ tục, Hàm:
Tên phải hàm ý về nội dung giải quyết của nó. Điều quan trọng là không được trùng với từ khóa của Excel. Ví dụ không được đặt tên là "Sub", "Do", "Loop" hay các hàm sẵn có của VBA là "Left", "Right",...

Ví dụ tôi muốn tạo một hàm để tìm chuỗi, vậy tên tôi sẽ đặt tên function là "Timchuoi", "BatdaulaChuhoa" là hàm đổi các ký tự đầu của mỗi từ thành chữ hoa (Trong Excel có hàm Proper để làm nhưng hàm này bị lỗi với font với kiểu gõ không phải Unicode và có dấu), tại sao không đặt là "Chuhoa" để ngắn hơn? Vì có thể bị nhầm sang đổi chuỗi thành chữ hoa (UPPER, VBA-Ucase).
Chúng ta đặt tên sao cho không bị nhầm chức năng.
Trong VBA khai báo như sau

Function Timchuoi()
End Function

Function BatdaulaChuhoa()
End Function


+ Tên Dim, Const:
Cách thức cũng như phần đặ tên cho Sub/Function nhưng thêm các ký tự định nghĩa để làm sáng tỏ kiểu giá trị (Type)
Kiểu giá trị gồm: String, Byte, Integer, Long, Date, Object, Boolean....
Với tôi, tôi hay đặt tên với phần đầu là kiểu giá trị, các kiểu Byte, Integer, Long thì dùng chữ "n"-Number để đại diện vì cơ bản là giá trị số. Kiểu Boolean thì dùng chuỗi "Is".

Dim strHoTen as String
Dim IsNam as Boolean
Dim dNgay as Date
......
Khi tôi viết hướng dẫn sử dụng hàm LEFT trên Excel tôi viết cấu trúc thế này LEFT(strChuoi, nKytu). Như vậy thì ta hiểu đối số đầu tiên là kiểu String - Chuỗi văn bản, nKytu là giá trị đưa vào kiểu số.

Có nhiều bạn khi khai báo kiểu giá trị thường hay bỏ lửng như Dim strHoTen mà không có kết thúc là "String" - Không nên chút nào! Việc xác định rõ giá trị còn là quy ước khi sử dụng chúng trong thân chương trình.

+ Xác định tham số cho Sub, Function
Nhắc lại về hàm LEFT(strChuoi, nKytu). Chúng ta cứ tự hỏi tại sao phải có 2 đối số? Tại sao? Muốn lấy bên trái với n ký tự thì buộc người dùng phải đưa vào strChuoi - chuối để lấy, nKytu là số ký tự cần lấy.

Như vậy tham số cho Sub, Function là những tham số mà người dùng phải buộc đưa vào thì Sub, Function mới xử lý được. Tên các tham số này người dùng (bất kỳ ai sử dụng) phải gần như tự đọc hiểu được).

Có một ví dụ về kiểu khai báo thế này
Function Tachten(St as String,Bt as Integer)
St, Bt là cái gì? Viết thế này thì chỉ có tác giả mới hiểu và đến lúc nào đó chính họ sẽ không biết nó là cái gì nữa!

Khi đưa biến vào làm tham số chúng ta cũng cần chú ý một cách để Optional - Tùy ý và gán giá trị ngầm định.

Ví dụ
Function Timchuoi(Byval strChuoi as String,Byval strChuoiTim as String, Optional Byval TuBenTrai as Boolean = True) as Long
End Function
Hàm "Timchuoi" để tìm strChuoiTim trong strChuoi, ngầm định (Optional) tìm từ trái sang phải.
A1="090 4210337"
=Timchuoi(A1," ")
Hàm sẽ tìm ký tự " " trong ô A1 và trả về vị trí tìm được, chúng ta nếu tìm từ trái thì không cần phải vào tham số thứ 3 vì ngầm định TuBenTrai=True rồi
Nếu tìm từ bên phải thì =Timchuoi(A1," ", False)

Chúng ta gán Optional đầu tiên trước khai báo Byval hay Byref khi biết chắc đa số mọi người sẽ quy ước biến này về một giá trị nào đó, sử dụng Optional để người dùng sử dụng ngắn gọn hơn (Bản chất là ta khai báo giá trị tham số giúp cho người dùng).

2- Tạo ra Sub, Function để giải quyết mấu chốt công việc, khai thác triệt để các hàm sãn có
Chúng viết các Sub, Function là để giải quyết mấu chốt công việc, không nên quá cụ thể nếu điều đó không phải là bắt buộc.

Tôi sẽ viết hàm "Timchuoi". Hàm này sẽ tìm chuỗi từ trái sang phải hoặc ngược lại, kết quả tìm được sẽ cho ra một số >0 là vị trí tìm được, =0 nếu không tìm được.

Cách 1

Function Timchuoi(Byval strChuoi as String, Byval strChuoiTim as String, Optional Byval TuBenTrai as Boolean = True) as Long
Dim I as Long
Dim nKytuChuoitim as Long
Dim nKytuChuoi as Long
nKytuChuoi=Len(strChuoi)
nKytuChuoitim =Len(strChuoiTim)

If nKytuChuoi<nKytuChuoitim then Exit Function

If TuBenTrai Then
For I=1 To nKytuChuoi
If Mid(strChuoi,I,nKytuChuoitim)=strChuoiTim Then
Timchuoi=I
Goto Done:
End if
Next I
Else
For I=nKytuChuoi To 1 Step -1
If Not (nKytuChuoi-I< nKytuChuoitim) Then
If Mid(strChuoi,I,nKytuChuoitim)=strChuoiTim Then
Timchuoi=I
Goto Done:
End if
End if
Next I
End If

Done:
End Function

Mặc dù Cách 1 Khá chặt chẽ nhưng không hay chút nào vì vừa dài lại vừa không khai thác các hàm mà VBA đã cung cấp->Tốc độ xử lý rất có thể bị chậm hơn nhiều với việc áp dụng hàm đã có

Cách 2 'Khai thác hàm đã có Instr và InstrRev

Function Timchuoi(Byval strChuoi as String, Byval strChuoiTim as String, Optional Byval TuBenTrai as Boolean = True) as Long
Dim I as Long
Dim nKytuChuoitim as Long
Dim nKytuChuoi as Long
nKytuChuoi=Len(strChuoi)
nKytuChuoitim =Len(strChuoiTim)

If nKytuChuoi<nKytuChuoitim then Exit Function

If TuBenTrai Then
Timchuoi=Instr(strChuoi,strChuoiTim)
Else
Timchuoi=InstrRev(strChuoi,strChuoiTim)
End If

End Function


Ứng dụng hàm "Timchuoi"
+ Hàm tách tên
Function TachTen(Byval strHoTen as String) as String
TachTen=Mid(strHoTen,Timchuoi(strHoTen," ",False)+1)
End Function
+ Tách tên
Giả sử cột A là Họ và tên. Cần tách tên
Cách 1
=MID(A1,Timchuoi(A1," ",False)+1)
Cách 2
=TachTen(A1)

+ Tách dịch vụ điện thoại di động theo mã số
Giả sử cột A là các số điện thoại 090 4210337; 091 3255126; 098 555444; 0916 066512...
Cần lấy mã dịch vụ
=LEFT(A1,Timchuoi(A1," ")-1)
+ Từ số điện thoại cố định, tách mã vùng
Giả sử cột A là các số điện thoại 04 7544525 08 899655; 051 545222; 020 123456;...

=LEFT(A1,Timchuoi(A1," ")-1)

+ Tách tên tệp ra khỏi đường dẫn
'Sử dụng trong môi trương VBE
Sub VD()
Dim strFullPath as String
Dim strFileName as String

strFullPath = ActiveWorkbook.FullPath
strFileName=Mid(strFullPath,Timchuoi(strFullPath,"\",False)+1)
'Thông báo
Msgbox strFileName,,strFullPath
End Sub

Như vậy chỉ có một hàm "Timchuoi" mà giải quyết được những vấn đề về cắt chuỗi theo các mục đích khác nhau.

Vấn đề tôi muốn nhấn mạnh là chúng ta viết hàm không phải để nó chỉ giải quyết một việc cụ thể mà nó phải giải quyết những bào toán tổng quát. Hàm như một linh kiện máy tính PC có thể lắp vào máy này hay máy khác.

Việc viết hàm và thủ tục còn có rất nhiều các thuật toán hay giúp cho bài toán của bạn được đánh giá ử mức tối ưu. Việc đặt tên cũng vậy còn nhiều trường hợp để đặt khác. Trong phạm vi một bài viết ngắn tôi chỉ có thể đưa ra những lý giải cơ bản và ví dụ nhỏ, các bạn xem và tự tích tũy dần những kiến thức cũng như kinh nghiệm về việc coding.
 
Khóa học Quản trị dòng tiền
Secret_grasses

Secret_grasses

Guest
Cám ơn anh, bài viết của anh rất thú vị. Mong anh sẽ tiếp tục post những bài hướng dẫn về những kinh nghiệm khi viết code và đưa ra những bài tập nho nhỏ để dễ tiếp cận và dễ hiểu hơn.:1luvu:
 
HongViet

HongViet

Cao cấp
10/11/05
286
10
18
Đà nẵng
Đúng là tuyệt tác!

Rất bài bản cho ~ chương trình tầm cỡ!
Còn khi xài thì tuỳ mục đích mà sử dụng công cụ, dao hay kéo, hay gì khác để cắt 1 vật!:angel:
 
L

lehongduc

Trung cấp
29/3/05
131
1
18
65
VietNam
Xin chào các Bác,
Xin bàn thêm 1 ý:
Hàm InstrRev trong đoạn "Timchuoi=InstrRev(strChuoi,strChuoiTim)" không thể sử dụng được trong Excel 97, bởi: với phiên bản VBA tương ứng không tích hợp hàm này, InstrRev chỉ có trong Excel 2000 trở về sau.
 
S

SA_DQ

Thành viên Cố vấn - Webketoan Mentors
29/6/05
595
104
43
67
HCM city
Ông thầy dạy cách lãng fí đây?!

Tuanktcdcn nói:
Cách 1. . .Cách 2Khai thác hàm đã có Instr và InstrRev

Function Timchuoi(Byval strChuoi as String, Byval strChuoiTim as String, Optional Byval TuBenTrai as Boolean = True) as Long
1Dim I as Long
2Dim nKytuChuoitim as Long
3Dim nKytuChuoi as Long
4nKytuChuoi=Len(strChuoi)
5nKytuChuoitim =Len(strChuoiTim)
6If nKytuChuoi<nKytuChuoitim then Exit Function

If TuBenTrai Then
Timchuoi=Instr(strChuoi,strChuoiTim)
Else
Timchuoi=InstrRev(strChuoi,strChuoiTim)
End If

End Function
.
:dance2:
/(/hững lãng fí theo thiển í, được liệt kê như sau:
a/. Câu lệnh 1 không dùng (thông cảm do lịch sử để lại)!
b/. Câu lệnh 2 & 3 khai As Long là lãng fí không cần thiết; Nếu ai đó cố tình tạo ra chuỗi kí tự hay kí số dài hơn 2 triệu thì chuyển đến "Biên hoà" cho rồi!
c/. Các câu lệnh từ 2 - 6 có thể thay = câu:
26 If Len(nKiTuChuoi) < Len( nKiTuChuoiTim) Then Exit Function
Lời nhắn CC: Cần tiêt kiệm tài nguyên; Vì nước ta còn nghèo lắm!:angel: :drummer:
 
T

Tuanktcdcn

Lão già ham vui
18/6/04
549
52
28
48
Hà Nội
www.bluesofts.net
lehongduc nói:
Xin chào các Bác,
Xin bàn thêm 1 ý:
Hàm InstrRev trong đoạn "Timchuoi=InstrRev(strChuoi,strChuoiTim)" không thể sử dụng được trong Excel 97, bởi: với phiên bản VBA tương ứng không tích hợp hàm này, InstrRev chỉ có trong Excel 2000 trở về sau.

Đúng vậy! Chính xác là InstrRev không có trong Office 97 (VBA6.DLL). Các bạn nên loại bỏ Office97 đi vì các lý do cơ bản:
Sản phẩm mới:
- Sản phẩm mới bao giờ cũng sửa lỗi mà các version cũ có
- Tăng nhiều tiện ích người dùng
- Tốc độ truy xuất file nhanh hơn
- Trong VBA-Cung cấp các hàm tiện dụng hơn
- Trong VBA cho phép khai báo Enum
......
Với bộ Office các bạn nên sử dụng tối thiểu từ Office2000 trở lên.
Office2000 không yêu cấu máy cấu hình cao lắm, kể cả khi bạn vẫn dùng Pentium(R) 133 MHZ RAM32

To SA_DQ: nKytuChuoi=Len(strChuoi)
nKytuChuoitim =Len(strChuoiTim)

Trong Hàm Timchuoi() đúng là có thể không cần khai báo trên. Với các thủ tục khác nếu trong thân chương trình còn dùng tới độ rộng của chuỗi (LEN) nó thì nên có để kế thừa phép tính trước mà không phải tính lại.

Tiết kiệm là điều chúng ta phải tính chứ, nhưng vấn đề tiết kiệm ở đây phải hiểu đúng.
Trong một thủ tục:
1-> Khai báo tài nguyên
2-> Sử dụng tài nguyên
3-> Giải phóng tài nguyên

Nếu thiếu bước 3 thì ứng dụng của bàn sẽ dần tới chỗ cạn kiệt và break.

Trong một thủ tục, nếu không phải là biến đối tượng (Dim obj As Object; Set obj=...) thì khi kết thúc thủ tục thì chúng tự được giải phóng (Free/Dispose). Nếu chúng ta không khai báo mà vẫn dùng biến đây không phải là cách tốt - Không chặt chẽ và một nơi nào đó của hệ thống vẫn còn nhớ biến đó.

Mong các bác tiếp tục viết ra những gì mình biết và đang quan tâm, chúng ta tiếp tục thảo luận.
 
hai2hai

hai2hai

VNUNI Makes a difference
29/4/04
2,030
125
63
51
Hà nội
vnuni.net
SA_DQ nói:
/(/hững lãng fí theo thiển í, được liệt kê như sau:
b/. Câu lệnh 2 & 3 khai As Long là lãng fí không cần thiết; Nếu ai đó cố tình tạo ra chuỗi kí tự hay kí số dài hơn 2 triệu thì chuyển đến "Biên hoà" cho rồi!

Nếu ai hiểu chương trình dịch nó hoạt động như thế nào thì khai báo Long tuy tốn chút mem nhưng lại chạy nhanh hơn và dân lập trình chuyên nghiệp (bọn M$ ấy) nó toàn dùng kiểu Long thôi chứ ít dùng Interger lắm. Giải thích: Kiểu gì khi sang mã máy, compiler nó đều thêm 1 lệnh chuyển kiểu Interger sang kiểu Long. Vì vậy tôi hay khai báo As Long cho chương trình chạy nhanh (mem thì bây giờ thiếu gì).

SA_DQ nói:
c/. Các câu lệnh từ 2 - 6 có thể thay = câu:
26 If Len(nKiTuChuoi) < Len( nKiTuChuoiTim) Then Exit Function

Mọi người thử phân biệt 2 cách viết xem cách viết nào nhanh hơn nhé:

For i% = 1 to Len(nKiTuChuoi)
....
Next



lngStringLen% = Len(nKiTuChuoi)
For i% = 1 to lngStringLen%
....
Next

Nếu mọi người tìm ra được chân lý thì tự khắc mọi người hiểu tại sao phải dùng thêm 2 biến. Vì đây là hàm quá đơn giản (chỉ là 1 ví dụ thôi nên có thể mọi người chưa thấy được chân lý đó). Lập trình ko chỉ là làm cho code chạy. Lập trình là cả 1 bề dày kinh nghiệm học hỏi liên tục kèm theo những kỹ năng, những nguyên tắc cần tuân thủ, những bản chất gốc gác của nền tảng (ví dụ phải hiểu windows programming,...) thì tự nhiên thấy trở nên professional.

À, té ra Tuân đã nói vần đề này rồi :) -->

To SA_DQ: nKytuChuoi=Len(strChuoi)
nKytuChuoitim =Len(strChuoiTim)

Trong Hàm Timchuoi() đúng là có thể không cần khai báo trên. Với các thủ tục khác nếu trong thân chương trình còn dùng tới độ rộng của chuỗi (LEN) nó thì nên có để kế thừa phép tính trước mà không phải tính lại.

Tiết kiệm là điều chúng ta phải tính chứ, nhưng vấn đề tiết kiệm ở đây phải hiểu đúng.
Trong một thủ tục:
1-> Khai báo tài nguyên
2-> Sử dụng tài nguyên
3-> Giải phóng tài nguyên
 
HongViet

HongViet

Cao cấp
10/11/05
286
10
18
Đà nẵng
hai2hai nói:
Nếu hiểu chương trình nó hoạt động như thế nào thì khai báo Long tuy tốn chút mem nhưng lại chạy nhanh hơn và dân lập trình chuyên nghiệp (. . .) nó toàn dùng kiểu Long thôi. Giải thích: Kiểu gì khi sang mã máy, compiler nó đều thêm 1 lệnh chuyển kiểu sang kiểu Long. Vì vậy khai báo As Long cho chương trình chạy nhanh ().
Quả là hay và quá hay! Đáng đồng tiền bát gạo!


nói:
Mọi người thử phân biệt 2 cách viết xem cách viết nào nhanh hơn nhé:
For i% = 1 to Len(nKiTuChuoi)
....
Next

lngStringLen% = Len(nKiTuChuoi)
For i% = 1 to lngStringLen%
....
Next
Nếu mọi người tìm ra được chân lý thì tự khắc mọi người hiểu tại sao phải dùng thêm 2 biến.
Phải vầy không, Bác 2Hai2: Nếu Len(nKiTuChuoi) = 8 thì vòng lập đầu phải thực hiện 16 lệnh! Chính xác chưa vậy B.?!
Quả là 1 ngày đường một sàng khôn!
 
Đào Việt Cường

Đào Việt Cường

Moderator
22/11/05
400
4
18
Khánh Hòa
Dear all,
--------
Em thì chưa biết nhiều về chân lý mấy! Nhưng em cảm nhận thế này:
- Nếu Len(nKiTuChuoi) = 8 thì cả hai vòng đều lặp 8 lần, còn thực hiện bao nhiêu lệnh thì còn phụ thuộc vào số lượng các câu lệnh bên trong nó.
- Khi khai gán lngStringLen = Len(nKiTuChuoi) thì khi lặp, nó không phải tính lại Len(nKiTuChuoi) nữa.
Em mạo muội anh 2 kết luận: Chính xác!
 
Đào Việt Cường

Đào Việt Cường

Moderator
22/11/05
400
4
18
Khánh Hòa
Dear all,
--------
Em thì chưa biết nhiều về chân lý mấy! Nhưng em cảm nhận thế này:
- Nếu Len(nKiTuChuoi) = 8 thì cả hai vòng đều lặp 8 vòng, còn thực hiện bao nhiêu lệnh thì còn phụ thuộc vào số lượng các câu lệnh bên trong nó.
- Khi gán lngStringLen = Len(nKiTuChuoi) thì khi lặp, nó không phải tính lại Len(nKiTuChuoi) nữa.
Em mạo muội anh 2 kết luận: Chính xác!
 
L

lehongduc

Trung cấp
29/3/05
131
1
18
65
VietNam
Xin được diễn đạt nông dân hơn như thế này

HongViet nói:
Quả là hay và quá hay! Đáng đồng tiền bát gạo!



Phải vầy không, Bác 2Hai2: Nếu Len(nKiTuChuoi) = 8 thì vòng lập đầu phải thực hiện 16 lệnh! Chính xác chưa vậy B.?!
Quả là 1 ngày đường một sàng khôn!
Xin chào các Bác,
Để cho các bạn mới vọc VBA (và cũng là mới bắt đầu thảo chương) đỡ mất thời gian, tôi xin góp thêm ý diễn đạt nôm na là vầy:
+ Nếu cứ để For i%=1 to Len(nKytuChuoi) ... thì cái ứng dụng nó buộc phải xử lý 1 vòng bằng hàm Len với cái chuỗi nKytuChuoi. Cứ đụng tới cái đọan bạn ghi là Len(nKytuChuoi) nó lại mần tiếp cái chuyện ấy.
+ Thế là rất mất thời gian, chi bằng ta tính 1 lần ngay từ đầu Len(nKytuChuoi) bằng bao nhiêu rồi gán quách nó cho 1 biến gọi là lngStringLen. Sau đó cái ứng dụng chỉ cần lấy giá trị của biến này để xơi mà khỏi phải bận tâm mần răng để có nó nữa.
Kính các Bác nhé.
 
hai2hai

hai2hai

VNUNI Makes a difference
29/4/04
2,030
125
63
51
Hà nội
vnuni.net
Thực ra sau khi đưa ví dụ đó thì nhìn là hiểu đoạn code nào chạy nhanh hơn rồi :)

Cũng tương tự như vậy, mỗi khi thực hiện oRS_Customer.EOF thì ADO Engine nó phải làm những thao tác gì (Cái này làm DB phải tìm hiểu rõ từng lệnh 1). Và như vậy, 1 triệu bản ghi - 1tr vòng lặp --> thì nó lại thực hiện 1tr lần cái công việc đó (Ít bản ghi thì mọi người ko nhận thấy sự khác biệt đâu).

Hãy tìm cách lấy được tổng số bản ghi trước và sau đó dùng vòng For thì khi có nhiều đến vài triệu bản ghi, mọi người sẽ thấy cải thiện đáng kể.

'// Đây là đoạn code khá ... ko tốt :) (và sure luôn là rất nhiều người viết kiểu này)
Do While Not oRS_Customer.EOF '// Khi kiểm tra EOF cũng phải thực hiện khá nhiều thao tác mà ta có thể không biết (để biết thì phải đọc khá kỹ).
...
oRS_Customer.MoveNext '// Mỗi lần Move Next lại phải làm khá nhiều thao tác mà bình thường ta ko hề biết.

End Do

Tóm lại, trong bất kỳ vòng lặp nào cần chú ý hạn chế tối đa những tiến trình consume long time. v.v....

Và còn nhiều điều trong lập trình nói chung, lập trình CSDL nói riêng cần phải optimize lắm.

Hy vọng mọi người ngày càng có nhiều chia sẻ cho nhau. Và hãy bắt đầu ngay bằng việc .... CODING CONVENTION (Điều mà mình thấy rất thiếu khi mọi người bàn đến chuyện lập trình ở đây).
 
L

lehongduc

Trung cấp
29/3/05
131
1
18
65
VietNam
Xin chào,
Ngày nào tôi cũng đánh vật với ba cái xử lý Database nên xác nhận điều Bác hai2hai đã nêu là chính xác.
Tóm lại cứ phép toán nào cần lấy kết quả mà phải qua nhiều công đoạn xử lý hoặc phải duyệt qua nhiều mẫu tin trong 1 bảng dữ kiện thì cách tốt nhất luôn luôn là: nếu có cách tính trước được các chỉ số ổn định cần lấy (không biến thiên trong quá trình xử lý) thì tính trước rồi gán vào cho 1 biến xác định, hết sức tránh việc mỗi lần cần lại phải tính. Điều này đúng cho 1 Procedure (Sub hoặc Function) cũng đúng khi xét cho cả 1 ứng dụng.
 
HongViet

HongViet

Cao cấp
10/11/05
286
10
18
Đà nẵng
Xin í kiến của 2 bác chút nữa?!

lehongduc nói:
1./ Sub Mot()
Dim DAu As Long: Dim Cuoi As Long
Dau = 5! + 3! : Cuoi = 7! - 1!
If Dau > Cuoi then MsgBox "Nhanh"
End Sub
2./ Sub Hai()
If 5! + 3! > 7! - 1 ! Then MsgBox "Chậm hơn?"
End Sub
Thì cái nào chuẩn/nhanh hơn vậy các B.?!
BS ngày hôm nay:
haì2hai nói:
Bạn chưa đọc kỹ rồi, bạn đọc cái đoạn mà tớ trích của Tuân ấy
(/ậy bạn đã đọc kỹ bài người khác viết chưả?! Bài #5 ấy?!
 
Sửa lần cuối:
HongViet

HongViet

Cao cấp
10/11/05
286
10
18
Đà nẵng
Xin í kiến của 2 bác chút nữa?!

Nhờ xoá dùm Mode nào í ơi!
 
hai2hai

hai2hai

VNUNI Makes a difference
29/4/04
2,030
125
63
51
Hà nội
vnuni.net
Bạn chưa đọc kỹ rồi, bạn đọc cái đoạn mà tớ trích của Tuân ấy (Chỉ dùng biến khi sử dụng lại để khỏi phải tính toán (vậy 2 cái sub đó có sử dụng lại nhiều ko?, banana thế ko biết)). Chỉ ko áp dụng nhiều lắm với những hàm chỉ có 1 hoặc 2 dòng vì nó chỉ thực hiện có 1 lần thôi.
Vậy bạn đã đọc kỹ bài người khác viết chưa?! Bài #5 ấy?!

Thôi, miễn góp ý. Tôi đây muốn nói chuyện tổng quan trong lập trình chứ đâu chỉ là 1 cái hàm con con nào đó. Mấy dòng code con con này chả liên quan gì đến tôi nữa. BB

PS: Lần sau đừng nhắn tin PM cho tôi mấy chuyện này nữa đấy nhé. Mất công (& mất 1 phút) vào delete.
 
Sửa lần cuối:
L

lehongduc

Trung cấp
29/3/05
131
1
18
65
VietNam
Thêm 1 hàm nữa, mời các Bạn thảo luận.

Xin mời các Bạn thảo luận hàm do tôi tự biên tự diễn sau nhé:
+ Để cho việc thảo luận có hiệu quả, sau khi các thành viên thảo luận xong rất mong Bác Mod cho 1 cái tổng kết với hàm đã được hiệu chỉnh lại tối ưu nhất.
+ Cái hàm này có tác dụng cắt lấy chuỗi con từ bên trái hoặc bên phải 1 chuỗi mẹ đến 1 ký tự xác định. Chúng ta có thể dùng các hàm có sẵn của Excel như Left, Right và Instr để đáp ứng nhu cầu này, song theo tôi trong một số trường hợp ta buộc phải viết 1 hàm bằng VBA mới xử lý được, đó là lý do của việc tôi thấy cần viết cái hàm này. Ý các Bạn ra sao?

Function CutLoR(St As String, Char As String, N As Boolean)
'
'Cat lay chuoi con tu ben trai hay ben phai chuoi me den ky tu xac dinh
'Char: ky tu xac dinh
'n=true => cat ben trai, n=false => cat ben phai
'
Dim Sb As String, stChk As String
Dim i As Integer, LngSt As Integer
St = Trim(St)
LngSt = Len(St)
If LngSt = 0 Then Exit Function
For i = 0 To LngSt
If N = True Then 'Cat trai
stChk = Mid(St, i + 1, 1)
Else
stChk = Mid(St, Len(St) - i, 1)
End If
If stChk <> Char Then
If N = True Then
Sb = Sb & stChk
Else
Sb = stChk & Sb
End If
Else
Exit For
End If
Next i

CutLoR = Sb

End Function
 
L

lehongduc

Trung cấp
29/3/05
131
1
18
65
VietNam
Xin các Bác đừng mích lòng nhau để cùng góp cho cộng đồng

Các Bác ơi,
Tôi khoái cái WKT vì tinh thần cộng đồng và nhiệt tâm đóng góp của Các Bác trên WKT. Cũng vì vậy, mong các Bác hãy nhẹ lời với nhau, và cũng đừng mích lòng chi nhau để cùng nhau đóng góp cho cộng đồng.
Xin đề nghị Bác chủ nhiệm cố gắng có gút lại từng vấn đề để việc thảo luận có kết quả tốt hơn.
Cầu chúc các Bác luôn mạnh giỏi.
* Xin tái bút: trong cái đoạn code của tin trước tôi đã cố gắng cho các dòng thụt vào thụt ra để dễ coi, mà sao mần hoài mà các dòng vẫn cứ thẳng tưng, trông khó coi quá. Xin Bác chủ nhiệm giúp một tay và truyền lại bí quyết định dạng.
 
Sửa lần cuối:
hai2hai

hai2hai

VNUNI Makes a difference
29/4/04
2,030
125
63
51
Hà nội
vnuni.net
lehongduc nói:
* Xin tái bút: trong cái đoạn code của tin trước tôi đã cố gắng cho các dòng thụt vào thụt ra để dễ coi, mà sao mần hoài mà các dòng vẫn cứ thẳng tưng, trông khó coi quá. Xin Bác chủ nhiệm giúp một tay và truyền lại bí quyết định dạng.

Tại trong post, các admin đã disable thẻ (tag) Code đi rồi nên ko hiển thị được theo nguyên bản. Tuy nhiên, muốn xem được tình trạng nguyên bản của nó thì bấm vào nút Quote (Trích dẫn) lại cái bài ấy và copy ra mà xem. Đảm bảo đúng kiểu thụt ra/vào.

Nhân tiện cái hàm trên, mình muốn nhắc lại là mọi người nên chú ý về coding convention & optimize code 1 chút.
Ví dụ: CutLoR(St As String, Char As String, N As Boolean) đọc sẽ rất khó hiểu (mọi người thử xem cách mà M$ nó declare API xem có dễ hiểu ko?

Char là 1 ký tự: Ví dụ A, B, C. Hiện nếu mình viết tên hàm, tên biến đều tiếng Việt và tự nhiên có 1 biến lại dùng từ tiếng anh là rất khó đọc (nếu ko muốn nói là đọc ko hiểu gì cả).

Đặc biệt là những từ viết tắt như: Dim Sb As String '// --> Hầu như ko hiểu biến này có mục tiêu là gì.

Về chuyện optimize code. Ở đây chúng ta dùng khá nhiều hàm xử lý String mà mọi người có thể chưa biết là chỉ cần thêm $ sau tên hàm là tốc độ cũng tăng lên so với khi mình ko viết (dĩ nhiên điều này chỉ thấy hiệu quả khi phải sử lý với khối lượng công việc lớn). Ví dụ: Thay vì Mid() thì ta viết Mid$(), Trim() thì viết Trim$(), v.v...

Cao cấp hơn, để sử lý string thì có thể dùng CopyMem nhưng có lẽ lựa chọn này khá cao cấp và ko cần thiết với mọi người.
 
Sửa lần cuối:
hai2hai

hai2hai

VNUNI Makes a difference
29/4/04
2,030
125
63
51
Hà nội
vnuni.net
Hàm này là 1 hàm khá đơn giản, có mục đích rõ ràng (Bấm vào nút Trích dẫn để xem). Mọi người có thể tự viết phần thân cho hàm này. Tuy nhiên code được đánh giá cao nhất là code viết theo coding conventions (hungarian naming conventions).

Function SMid(orig_string As String, start As Long, str_start As String, str_end As String)
'****************************************************************************************************************************************************
' Name: SMid - "Smart" Mid
' Description: This function is similar to the Mid function.
' Except, you can specify the starting, and ending strings
' (capture the data in between).
' Inputs:
' - orig_string As String : Source string
' - start As Long : Location in source to start from
' - str_start As String : beginning string (capture from)
' - str_end As String : ending string (capture to)
' o_string = Origional String
' s_start = Start From string
' s_end = Ending string
' Returns:This code will return the data
' that is found between the "str_start" and "str_end" strings.
' Example:
' newStr = SMid("Hello 1Between2 world!", 1, "1", "2")
' will return: "Between"
' By: hai2hai - VNUNI
'********************************************************************************

'// Please, your code should be here....
 

Xem nhiều