Bài tập về vòng lặp

Liên hệ QC

ndu96081631

Huyền thoại GPE
Thành viên BQT
Super Moderator
Tham gia
5/6/08
Bài viết
30,703
Được thích
53,930
Những ai đã từng xem qua bài viết này: Giới thiệu Cơ bản về vòng lặp For . . . next của sư phụ ptm0412 giờ hãy cùng làm 1 vài bài tập từ đơn giản đến nâng cao nhé
Xin mở màn bằng 1 bài tập sau:

Bài tập 01:

Hãy tính xem từ năm 1900 đến nay có bao nhiêu ngày thuộc dạng THỨ SÁU NGÀY 13
------------------------
Các bạn ai có bài tập gì hay xin post lên đây nhé! Cảm ơn
 
Chỉnh sửa lần cuối bởi điều hành viên:
Với chuỗi gồm 5 ký tự ban đầu sẽ có thể tạo ra 26^5 = 11 881 376 mã khác nhau

Nếu muốn liệt kê 120 000 mã thôi (khoảng 1% tổng số) khi đó có cần quan tâm đến tốc độ xử lý không?

Vấn đề code dài hay ngắn, dễ nhìn hay rối mắt liệu có quan trọng bằng so với việc cho code chạy 1 nhát thì ngỗi đợi như vô quán cafe hay què RAM ... Nên khi xử lý dữ liệu lớn, mình thường hay quan tâm đến tốc độ xử lý (thuật toán) và cách trình bày hơn so với việc rút gọn code hay trình bày code dễ nhìn.

Không hiểu rõ lắm ý của Boyxin?
Xin trình bày lại như sau:
- Mỗi người có thể nghĩ ra thuật toán khác nhau: Boyxin, tôi, huuthang, RollOver+ndu, gồm 4 thuật toán. Chúng ta sẽ cùng nghiên cứu mổ xẻ các thuật toán này và học hỏi lẫn nhau. Khi chúng ta thảo luận, các thành viên đang học sẽ thấy thêm nhiều ý kiến bổ ích, và cả chúng ta nữa. Thí dụ thuật toán của huuthang, tôi đã hiểu nhưng chưa áp dụng được cho đến khi huuthang đưa đáp án lên. Vô hình trung tôi cũng học thêm 1 cách hay!
- Về việc có nên cải thiện tốc độ không, thì tôi nghĩ đương nhiên là cần, nhất là máy yếu như máy của tôi hiện giờ (nói cho vui là què ram). Cả boyxin và tôi đêu dùng mảng để cải thiện tốc độ. Điều này cũng giúp cho các thành viên đang học có thêm nhiều tham khảo. Thiết nghĩ, dùng mảng để gán giá trị vào trước khi gán xuống sheet cũng không phải khó khăn lắm, MinhCong đã làm được đấy thôi.

boyxin đã viết:
Sau khi đạt kết quả đúng theo yêu cầu rồi thì mới tính đến chuyện nâng cấp, mởi rộng, ... Không biết các bác tính sao về vấn đề này

Theo tôi nghĩ và đã từng kinh nghiệm, có những thuật toán có thể nâng cấp, mở rộng, nhưng cũng có những thuật toán chỉ đành gạt nước mắt mà vứt bỏ. Thí dụ code của tôi, nếu Mã có độ dài bất kỳ cũng chưa biết sẽ cải tiến ra sao, hay là vứt đi nữa.

ndu đã viết:
Còn chuyện Function hay Sub em nghĩ nó cũng như nhau thôi mà sư phụ!

Không hẳn thế đâu, ngay cả tôi cũng đã đánh vật với việc chuyển Sub thành Function biết bao nhiêu lâu, và vẫn còn đang phải học.
 
Lần chỉnh sửa cuối:
Upvote 0
Các phương pháp mọi người đưa ra đều có 1 điểm chung là sử dụng hàm Chr và Asc để tăng 1 ký tự lên 1 đơn vị. Và ngoài cách của bạn huu_thang sử dụng phương pháp sử phép toán xử lý chuỗi ra, mọi người đều bị mắc 1 chỗ là khi tăng ký tự Z. Tôi xin gửi thêm 1 phương pháp kết hợp thêm 1 chút thủ thuật để dễ dàng xử lý hơn như sau
Mã:
Sub Ma3()
    Const sAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZA"
    Dim arrAlpha
    arrAlpha = Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A")
    
    Dim sText As String, N As Integer, i As Integer, j As Integer, iPos As Integer, sTemp As String
    sText = [A1]
    N = [A2]
    For i = 1 To N
        sTemp = ""
        For j = Len(sText) To 1 Step -1
            iPos = InStr(1, sAlpha, Mid(sText, j, 1))
            sTemp = arrAlpha(iPos) & sTemp
            If iPos < 26 Then Exit For
        Next
        sText = Left(sText, IIf(j = 0, 0, j - 1)) & sTemp
        Cells(i, 2) = sText
    Next
End Sub
Cũng xin nói thêm 1 chút về phương pháp của tôi và ndu đã đề cập, nó có cái hay riêng của nó. Giả sử cũng với 1 yêu cầu gần tương tự như thế này nhưng có 1 chút thay đổi như sau, nhập vào Mã ban đầu và số N, nhưng thay vì liệt kê ra N mã tiếp theo bằng đưa ra 1 mã thứ N tiếp theo mã ban đầu, khi đó các bạn sẽ thấy rõ sự khác biệt.
 
Upvote 0
Các phương pháp mọi người đưa ra đều có 1 điểm chung là sử dụng hàm Chr và Asc để tăng 1 ký tự lên 1 đơn vị. Và ngoài cách của bạn huu_thang sử dụng phương pháp sử phép toán xử lý chuỗi ra, mọi người đều bị mắc 1 chỗ là khi tăng ký tự Z. Tôi xin gửi thêm 1 phương pháp kết hợp thêm 1 chút thủ thuật để dễ dàng xử lý hơn như sau
Mã:
Sub Ma3()
    Const sAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZA"
    Dim arrAlpha
    arrAlpha = Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A")
    
    Dim sText As String, N As Integer, i As Integer, j As Integer, iPos As Integer, sTemp As String
    sText = [A1]
    N = [A2]
    For i = 1 To N
        sTemp = ""
        For j = Len(sText) To 1 Step -1
            iPos = InStr(1, sAlpha, Mid(sText, j, 1))
            sTemp = arrAlpha(iPos) & sTemp
            If iPos < 26 Then Exit For
        Next
        sText = Left(sText, IIf(j = 0, 0, j - 1)) & sTemp
        Cells(i, 2) = sText
    Next
End Sub
sAlpha và arrAlpha cũng gần gần giống nhau, sao bạn không bỏ bớt arrAlpha cho gọn.
Và bạn đặt tên Sub() là Ma3 người dùng sử dụng Excel phiên bản 2007 trở về sau sẽ gặp rắc rối.
PHP:
Sub Test()
    Const sAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZA"
    Dim arrAlpha
    Dim sText As String, N As Integer, i As Integer, j As Integer, iPos As Integer, sTemp As String
    sText = [A1]
    N = [A2]
    For i = 1 To N
        sTemp = ""
        For j = Len(sText) To 1 Step -1
            iPos = InStr(1, sAlpha, Mid(sText, j, 1))
            sTemp = Mid(sAlpha, iPos + 1, 1) & sTemp
            If iPos < 26 Then Exit For
        Next
        sText = Left(sText, IIf(j = 0, 0, j - 1)) & sTemp
        Cells(i, 2) = sText
    Next
End Sub
Cũng xin nói thêm 1 chút về phương pháp của tôi và ndu đã đề cập, nó có cái hay riêng của nó. Giả sử cũng với 1 yêu cầu gần tương tự như thế này nhưng có 1 chút thay đổi như sau, nhập vào Mã ban đầu và số N, nhưng thay vì liệt kê ra N mã tiếp theo bằng đưa ra 1 mã thứ N tiếp theo mã ban đầu, khi đó các bạn sẽ thấy rõ sự khác biệt.
Trường hợp này lại khác nữa. Mỗi bài toán có một cách giải quyết riêng. Và theo tôi, viết code không nên có tư tưởng viết để sau này gặp trường hợp khác lấy code đó ra xài luôn.
 
Lần chỉnh sửa cuối:
Upvote 0
sAlpha và arrAlpha cũng gần gần giống nhau, sao bạn không bỏ bớt arrAlpha cho gọn.
Và bạn đặt tên Sub() là Ma3 người dùng sử dụng Excel phiên bản 2007 trở về sau sẽ gặp rắc rối.
PHP:
Sub Test()
    Const sAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZA"
    Dim arrAlpha
    Dim sText As String, N As Integer, i As Integer, j As Integer, iPos As Integer, sTemp As String
    sText = [A1]
    N = [A2]
    For i = 1 To N
        sTemp = ""
        For j = Len(sText) To 1 Step -1
            iPos = InStr(1, sAlpha, Mid(sText, j, 1))
            sTemp = Mid(sAlpha, iPos + 1, 1) & sTemp
            If iPos < 26 Then Exit For
        Next
        sText = Left(sText, IIf(j = 0, 0, j - 1)) & sTemp
        Cells(i, 2) = sText
    Next
End Sub

Trường hợp này lại khác nữa. Mỗi bài toán có một cách giải quyết riêng. Và theo tôi, viết code không nên có tư tưởng viết để sau này gặp trường hợp khác lấy code đó ra xài luôn.
Gần giống nhau không có nghĩa là giống nhau bạn ạ, trong code bạn cũng đã thấy rồi, dùng thêm cái arrAlpha tôi có thể dùng luôn iPos làm chỉ số cho mảng mà chẳng cần phải dùng hàm MID. Còn có nên có tư tưởng viết để sau này gặp trường hợp khác lấy code đó xài luôn thì tùy vào mỗi người, dẫu sao trong trường hợp này nó vẫn là 1 cách làm, vấn đề này mà đem bàn ở đây thì e rằng không thích hợp. Còn trên thực tế mà hễ cứ gặp 1 tình huống mà chỉ viết code xử lý đúng tình huống đó, mà không xem xét các tình huống tương tự có thể gặp mà cover luôn thì e rằng tay của lập trình sẽ ngày 1 to ra vì phải gõ code nhiều.
 
Upvote 0
Còn trên thực tế mà hễ cứ gặp 1 tình huống mà chỉ viết code xử lý đúng tình huống đó, mà không xem xét các tình huống tương tự có thể gặp mà cover luôn thì e rằng tay của lập trình sẽ ngày 1 to ra vì phải gõ code nhiều.
Có lẽ do tôi không phải là một lập trình viên nên có quan điểm khác với lập trình viên.
Tôi chỉ nêu quan điểm của tôi và không muốn tranh luận về vấn đề này ở đây nữa.
 
Upvote 0
Các phương pháp mọi người đưa ra đều có 1 điểm chung là sử dụng hàm Chr và Asc để tăng 1 ký tự lên 1 đơn vị. Và ngoài cách của bạn huu_thang sử dụng phương pháp sử phép toán xử lý chuỗi ra, mọi người đều bị mắc 1 chỗ là khi tăng ký tự Z. Tôi xin gửi thêm 1 phương pháp kết hợp thêm 1 chút thủ thuật để dễ dàng xử lý hơn như sau
Mã:
Sub Ma3()
    Const sAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZA"
    Dim arrAlpha
    arrAlpha = Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A")
    
    Dim sText As String, N As Integer, i As Integer, j As Integer, iPos As Integer, sTemp As String
    sText = [A1]
    N = [A2]
    For i = 1 To N
        sTemp = ""
        For j = Len(sText) To 1 Step -1
            iPos = InStr(1, sAlpha, Mid(sText, j, 1))
            sTemp = arrAlpha(iPos) & sTemp
            If iPos < 26 Then Exit For
        Next
        sText = Left(sText, IIf(j = 0, 0, j - 1)) & sTemp
        Cells(i, 2) = sText
    Next
End Sub
.
Mình thì sẽ sửa đoạn
Mã:
arrAlpha = Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A")
thành:
Mã:
[/B]arrAlpha = Split(StrConv(sAlpha, 64), Chr(0))[B]
 
Lần chỉnh sửa cuối:
Upvote 0
Mình thì sẽ sửa đoạn
Mã:
arrAlpha = Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A")
thành:
Mã:
[/B]arrAlpha = Split(StrConv(sAlpha, 64), Chr(0))[B]
Hay quá, mình cũng thấy cần phải rút gọn mà chưa nghĩ ra, mới nghĩ đến for i và gán vào array.
Cám ơn nhiều.
 
Upvote 0
Bài tập về vòng lặp _ In theo danh sách filter

Muội có một data rất nhiều dữ liệu

- Tại cột A (cột Index --> có thể hiểu nó như các mã tài khoản) Các mã số này nằm rải rác không liên tục nhau

Bình thường muội vẫn phải filter và chọn theo thứ tự (mã Index để print) nhưng giờ muội muốn viết code in một lần được luôn

Muội đã nghĩ đến vòng lặp nhưng hiện tại chửa làm được, nhân tiện box bài tập về vòng lặp, xin gửi lên để nhận được trợ giúp

Xin cám ơn
 
Upvote 0
Muội có một data rất nhiều dữ liệu

- Tại cột A (cột Index --> có thể hiểu nó như các mã tài khoản) Các mã số này nằm rải rác không liên tục nhau

Bình thường muội vẫn phải filter và chọn theo thứ tự (mã Index để print) nhưng giờ muội muốn viết code in một lần được luôn

Muội đã nghĩ đến vòng lặp nhưng hiện tại chửa làm được, nhân tiện box bài tập về vòng lặp, xin gửi lên để nhận được trợ giúp

Xin cám ơn
Bài này có thể nói là RẤT DỂ nếu có dữ liệu đính kèm
Lọc duy nhất ta dùng Dictionary Object mà làm
 
Upvote 0
Bài tập về Lọc những ô ở cột A có tô màu. Em dùng vòng lặp như sau không biết như thế có gây lỗi gì không. Thấy chạy cũng đúng. Mong các Anh có ý kiến để Em còn học hỏi nhé!
Mã:
Sub Locmau()
 Dim enR, tmp(1 To 65536, 1 To 1), j, i As Long
  Range("B:B").Clear
   enR = Range("A65536").End(xlUp).Row
    For i = 1 To enR
        If Cells(i, 1).Interior.ColorIndex <> xlNone Then
            j = j + 1
            tmp(j, 1) = Cells(i, 1).Value
        End If
    Next
 Range("B1").Resize(j).Value = tmp
End Sub
 

File đính kèm

  • bai tap 1.xls
    26.5 KB · Đọc: 20
Upvote 0
Em rút gọn code này nhưng không được

PHP:
Set wf = Application.WorksheetFunction
socont = wf.Sum(wf.VLookup(Bill, bangsosanh, 16, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 17, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 18, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 19, 0))

Em rút gọn thành

PHP:
For i = 16 To 19
socont = wf.VLookup(Bill, bangsosanh, i, 0)
Next
socont = socont + socont

Em viết như trên nhưng dđược, các Huynh sửa cho em với

Cám ơn Ạh
 
Upvote 0
PHP:
Set wf = Application.WorksheetFunction
socont = wf.Sum(wf.VLookup(Bill, bangsosanh, 16, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 17, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 18, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 19, 0))

Em rút gọn thành

PHP:
For i = 16 To 19
socont = wf.VLookup(Bill, bangsosanh, i, 0)
Next
socont = socont + socont

Em viết như trên nhưng dđược, các Huynh sửa cho em với

Cám ơn Ạh
Bạn gởi kèm file lên để mấy Anh Em học hỏi với, chứ ghi code không thế thấy khó hình dung quá!
 
Upvote 0
PHP:
Set wf = Application.WorksheetFunction
socont = wf.Sum(wf.VLookup(Bill, bangsosanh, 16, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 17, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 18, 0)) + wf.Sum(wf.VLookup(Bill, bangsosanh, 19, 0))

Em rút gọn thành

PHP:
For i = 16 To 19
socont = wf.VLookup(Bill, bangsosanh, i, 0)
Next
socont = socont + socont

Em viết như trên nhưng dđược, các Huynh sửa cho em với

Cám ơn Ạh
Em xem lại socont = socont + socont nên nằm trong hay ngoài vòng lặp nhé.
 
Upvote 0
Em xem lại socont = socont + socont nên nằm trong hay ngoài vòng lặp nhé.

Nằm trong hay ngoài vòng lặp cũng sẽ cho kết quả sai.

1. Nằm trong:
- Cứ mỗi vòng lặp, socont lại lấy 1 giá trị mới.
- Kế đến, socont= socont + socont = 2 * socont. Kết quả này không lưu vào đâu hết
- Qua vòng lặp kế, lại vứt bỏ kết quả lần trước, nhận kết quả mới.

2. Nằm ngoài:
- Cứ mỗi vòng lặp, socont lại lấy 1 giá trị mới. Giá trị này cũng không lưu vào đâu hết
- Qua vòng lặp kế, lại vứt bỏ giá trị lần trước, nhận giá trị mới.
- Khi chạy đủ vòng, lấy giá trị cuối cùng, cộng với chính nó.

Tóm lại, phải có 1 biến tạm để lưu kết quả trung gian của mỗi vòng lặp. Thí dụ:

PHP:
For i = 1 To 10
    j = i ^2
    ketqua = ketqua + j
Next
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi nghĩ thế này

For
i = 16 To 19
socont
=
socont +wf.VLookup(Bill, bangsosanh, i, 0)
Next
 
Upvote 0
Tôi nghĩ thế này

For
i = 16 To 19
socont
=
socont +wf.VLookup(Bill, bangsosanh, i, 0)
Next
Vậy là OK rồi. cám ơn Anh.
Bác PTM ơi, em nói là xem lại để trong hay ngoài thôi mà, còn giải thuật thì thêm biến tạm hay của Anh Lê Tin là OK. Nhưng hình như thiếu phần phải set lại socont=0. Nếu code độc lập và chỉ tính có 1 cell thì không cần.
Cám ơn 2 anh.
 
Upvote 0
Biến tạm là nói về tổng quát. Trường hợp cụ thể sẽ không cần (như của anh LeTin).
Có trường hợp sẽ cần nếu như còn phải dùng giá trị tạm đó làm vài ba việc khác nữa.

Chứ thí dụ trong bài #196 chỉ cần thế này:

PHP:
For i = 1 To 10
    ketqua = ketqua +  i ^2
Next
 
Upvote 0
Upvote 0
Hóa ra lại phải viết như này he he, còn nếu trong công thức thì muội vẫn làm như vầy
Đó là vì xét về mặt thuật toán thì công thức mảng trong Excel y chang như vòng lập trong VBA! Tức:
- Trong bảng tính ta dùng mảng
- Trong VBA ta sẽ dùng vòng lập
Ẹc... Ẹc...
Từ đó mà suy luận tiếp
 
Upvote 0
Góp Hàm tìm s[FONT=&quot]ố lần xuất hiện nhiều nhất của 1 chữ số trong 1 số dương cho trước cho vui nhà vui cửa
Có gì sai xót xin góp ý dùm xin cảm ơn
[/FONT] [FONT=&quot]Ví dụ[/FONT]
[FONT=&quot] 112312 kết quả = 3(số 1 xuất hiện 3 lần)[/FONT]
[FONT=&quot]132333 kết quả = 4 ( số 3 xuất hiện 4 lần)[/FONT]



' --------dem so lan xuat hien cua tung so ----------------
Function Solan_a_xuathien_trong_n(ByVal n As Long, ByVal a As Byte) As Byte
Dim dem As Byte
dem = 0
Do While (n > 0)
If a = n Mod 10 Then dem = dem + 1

n = Int(n / 10)
Loop
Solan_a_xuathien_trong_n = dem

End Function

'----- tim so lan xuat hien nhieu nhat --------------'
Function kt_so_xuathien_nhieunhat(ByVal n As Long) As Byte
Dim max_xh As Byte
Dim sodu As Byte
Dim m As Long
m = n
max_xh = 0
Do While m > 0
sodu = m Mod 10
If (max_xh < Solan_a_xuathien_trong_n(n, sodu)) Then
max_xh = Solan_a_xuathien_trong_n(n, sodu)
End If
m = Int(m / 10)
Loop
kt_so_xuathien_nhieunhat = max_xh
End Function
 
Upvote 0
Web KT
Back
Top Bottom