Tìm vị trí cuối cùng của 1 giá trị được xác định (1 người xem)

  • Thread starter Thread starter An.BA
  • Ngày gửi Ngày gửi
Liên hệ QC

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

An.BA

Thành viên thường trực
Tham gia
15/9/18
Bài viết
214
Được thích
162
Giới tính
Nam
SG0038​
SG0038​
SG10035​
SG10035​
SG10035​
SG10040​

Em có 1 danh sách mã học sinh (khoảng vài trăm dòng) em sử dụng vòng lặp để đọc ra mã và lấy ra thông tin khác cùng dòng để load ra 1 ô tổng hợp dữ liệu
Nhưng nếu em sử dụng lặp từ 1 đến dòng cuối cùng thì e thấy load rất chậm vì nó chắc phải đọc qua từng dòng rồi so sánh.
Nên em muốn rút gọn bằng cách lặp từ vị trí đầu tiền tìm được đến vị trí cuối cùng tìm được
VD: MATCH (SG10035,A:A)=3 còn cuối cùng thì em chưa biết tìm thế nào ạ.
Công thức hiện tại của em đang là:

dong_cuoi = .Range("A5000").End(xlUp).Row For i = 2 To dong_cuoi ma = .Cells(i, "L").Value ' GAN MA HOC SINH nhom = .Cells(i, "T").Value 'NHOM DICH VU If UCase(ma) = mahs Then '' Lấy kết quả End IF Next i

Em cảm ơn ạ.
 
PHP:
Option explicit
Sub chang_biet_lay_gi()
const ma_hs ="ABC"
const start_row = 2
const col_ma = "L"
const col_nhom = "T"
Dim ds_ma as variant, ds_nhom as variant, last_row as long, i as long, j as long
Dim result as variant
With sheet1
last_row = .range("A" & .rows.count).end(xlup).row + 1
if last_row <= start_row then msgbox "khong co du lieu": exit sub
ds_ma = .range(col_ma & start_row & ":" & col_ma & last_row).value2
ds_nhom = .range(col_nhom & start_row & ":" & col_nhom & last_row).value2
last_row = ubound(ds_ma,1)-1
end with
redim result (1 to last_row, 1 to 1)
For i=1 to last_row
if vba.ucase$(ds_ma(i,1)) = ma_hs then
j=j+1
result (j,1)="chang_biet_lay_gi"
end if
next i
end sub
 
Upvote 0
PHP:
Option explicit
Sub chang_biet_lay_gi()
const ma_hs ="ABC"
const start_row = 2
const col_ma = "L"
const col_nhom = "T"
Dim ds_ma as variant, ds_nhom as variant, last_row as long, i as long, j as long
Dim result as variant
With sheet1
last_row = .range("A" & .rows.count).end(xlup).row + 1
if last_row <= start_row then msgbox "khong co du lieu": exit sub
ds_ma = .range(col_ma & start_row & ":" & col_ma & last_row).value2
ds_nhom = .range(col_nhom & start_row & ":" & col_nhom & last_row).value2
last_row = ubound(ds_ma,1)-1
end with
redim result (1 to last_row, 1 to 1)
For i=1 to last_row
if vba.ucase$(ds_ma(i,1)) = ma_hs then
j=j+1
result (j,1)="chang_biet_lay_gi"
end if
next i
end sub
Bạn ơi, mình vẫn thấy last_row đọc đến dòng cuối cùng bạn ạ.
Có thể nào làm nó đọc đến cái dòng cuối cùng của mã đó thôi không. Ví dụ ví trí đầu tiên tìm được là 3 ví trí cuối cùng là 15 thì nó chỉ lặp từ 3-15 thôi ạ
 
Upvote 0
@Chủ bài đăng: Nên xài phương thức FIND()

Bài này nếu bạn chủ tâm xài bỡi VBA thì bạn đã đăng bài sai mục rồi!
 
Upvote 0
@Chủ bài đăng: Nên xài phương thức FIND()

Bài này nếu bạn chủ tâm xài bỡi VBA thì bạn đã đăng bài sai mục rồi!
dạ, thì em chỉ cần xác định được bằng hàm nào cũng được để gán cho 1 ô trong excel xong em gọi nó ra từ VBA ạ.
Hàm find thì em chưa biết tìm thế nào ra được dòng cuối ạ
 
Upvote 0
Bạn ơi, mình vẫn thấy last_row đọc đến dòng cuối cùng bạn ạ.
Có thể nào làm nó đọc đến cái dòng cuối cùng của mã đó thôi không. Ví dụ ví trí đầu tiên tìm được là 3 ví trí cuối cùng là 15 thì nó chỉ lặp từ 3-15 thôi ạ
Hỡi chàng trai cứ chạy code đi rồi hãng nói.
Cỡ triệu dòng thì cũng chỉ nửa cái chớp mắt thôi.
Thứ nữa, tôi không biết bạn muốn cái gì. Tôi chỉ chỉnh code của bạn thôi. Bạn không nêu nổi vấn đề trong đầu ra ấy, cứ kể nể sự việc làm rối thêm.
Chỉ cần nói ra muốn làm gì là xong.
Nếu chỉ lấy giá trị đầu tiên tìm thấy thì thêm exit for vào sau chỗ tìm được kết quả.
 
Upvote 0
Bạn ơi, mình vẫn thấy last_row đọc đến dòng cuối cùng bạn ạ.
Có thể nào làm nó đọc đến cái dòng cuối cùng của mã đó thôi không. Ví dụ ví trí đầu tiên tìm được là 3 ví trí cuối cùng là 15 thì nó chỉ lặp từ 3-15 thôi ạ
Code duyệt hết nhưng vòng FOR rất nhanh vì duyệt mảng, không như bạn duyệt từng cell. Nếu bạn khẳng định rõ rệt là các mã trong cột L được sắp xếp thì
Mã:
hichic = False
For ....
    If ... = ma_hs then
        ...
        hichic = True
    ElseIf hichic then
        Exit For
    End If
Next
 
Upvote 0
Bạn có thể tham khảo theo file sau:
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, [f2]) Is Nothing Then
    Dim Rng As Range, sRng As Range:                             Dim NgSinh As Date
    Dim MyAdd As String, HTen As String

    Set Rng = Range([B1], [B2].End(xlDown))
    Set sRng = Rng.Find(Target.Value, , xlFormulas, xlPart)
    If Not sRng Is Nothing Then
        MyAdd = sRng.Address
        Do
            HTen = sRng.Offset(, 1):                             NgSinh = sRng.Offset(, 2).Value
            Set sRng = Rng.FindNext(sRng)
        Loop While Not sRng Is Nothing And sRng.Address <> MyAdd
    End If
    [h2].Value = HTen:                                            [j2].Value = NgSinh
End If
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Nếu dữ liệu đã sắp xếp thì dùng hàm Match với tham số 1 ở sau sẽ bảo nó tìm theo nhị phân. Và như vậy thì nhanh.
 
Upvote 0
Hỡi chàng trai cứ chạy code đi rồi hãng nói.
Cỡ triệu dòng thì cũng chỉ nửa cái chớp mắt thôi.
Thứ nữa, tôi không biết bạn muốn cái gì. Tôi chỉ chỉnh code của bạn thôi. Bạn không nêu nổi vấn đề trong đầu ra ấy, cứ kể nể sự việc làm rối thêm.
Chỉ cần nói ra muốn làm gì là xong.
Nếu chỉ lấy giá trị đầu tiên tìm thấy thì thêm exit for vào sau chỗ tìm được kết quả.
Mình có 1 bảng thông báo hiện tất cả nội dung của 1 mã học sinh.
1 Mã học sinh bao gồm rất nhiều nhóm dịch vụ.
1 nhóm dịch vụ bao gồm rất nhiều nội dùng được tách thành nhiều dòng
Mỗi 1 cell ghi chú sẽ hiện tất cả thông tin của nhóm dịch vụ đó tương ứng với mã.
Vậy nếu for lặp thì cứ mỗi 1 ô ghi chú nó sẽ lặp từ 1 đến cuối dòng cùng, và có hơn chục nhóm dịch vụ thì nó sẽ lặp lại như thế thêm hơn chục lần ạ.
Mình làm theo cách lặp từng dòng đó thì mỗi 1 mã mất 4 5s gì đó để nhảy xong ạ.
TTCHI TIẾT CÁC KHOẢN PHÍSố tiềnGhi chú
I
CÁC KHOẢN PHÍ ĐẦU NĂM​
0
1
Phí ghi danh​
0
2
Phí phát triển trường​
0
3
Phí dã ngoại​
0
4
Phí học phẩm​
0
5
Phí đồng phục​
0
IICÁC KHOẢN PHÍ THU THEO KỲ:
HỌC PHÍ, BÁN TRÚ, XE BUS
0
1
Học phí​
0
2
Phí DV bán trú​
0Từ ngày
Bài đã được tự động gộp:

Bạn có thể tham khảo theo file sau:
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, [f2]) Is Nothing Then
    Dim Rng As Range, sRng As Range:                             Dim NgSinh As Date
    Dim MyAdd As String, HTen As String

    Set Rng = Range([B1], [B2].End(xlDown))
    Set sRng = Rng.Find(Target.Value, , xlFormulas, xlPart)
    If Not sRng Is Nothing Then
        MyAdd = sRng.Address
        Do
            HTen = sRng.Offset(, 1):                             NgSinh = sRng.Offset(, 2).Value
            Set sRng = Rng.FindNext(sRng)
        Loop While Not sRng Is Nothing And sRng.Address <> MyAdd
    End If
    [h2].Value = HTen:                                            [j2].Value = NgSinh
End If
End Sub
Vâng đúng là ý em rồi ạ. Em cảm ơn ạ. Nhưng anh có thể giải thích qua giúp em với không ạ, để em hiểu thêm và áp dụng cho những trường hợp tương tự ạ

Code duyệt hết nhưng vòng FOR rất nhanh vì duyệt mảng, không như bạn duyệt từng cell. Nếu bạn khẳng định rõ rệt là các mã trong cột L được sắp xếp thì
Dữ liệu của em không được sắp xếp ạ. Bác có thể nói rõ hơn giúp em về vấn đề FOR duyệt mảng là như nào không ạ. Vì trong file của em em toàn là For 1 to dong_cuoi thôi ạ. và cứ thế rất nhiều chỗ em đều làm như vậy bảo sao load mãi mới ra ạ
 
Lần chỉnh sửa cuối:
Upvote 0
Công thức:
Dùng hàm Lookup, hoặc Match (cse)
tìm trị: =Lookup(2, 1/($a$1:$a$500="trị"), $b1:$b$500)
tìm dòng: {=Match(True, $a$1:$a$500="trị",True)}

VBA:
Nếu đã chép vào mảng rồi thì dò mảng từ dòng cuối ngược trở lên.
Nếu còn nằm trong range thì dùng phương thức Find; dò theo chiều ngược.

For i = Ubound(mang) To Lbound(mang) Step -1
If mang(i) = "trị" Then Exit For
Next i
If i >= Lbound(mang) Then
MsgBox "Xuất hiện lầ cuối ở vị trí " & i
Else
MsgBox "không tìm được"
End If

Set rg = Range("A1:A500")
Set where = rg.Find(what:="trị", after:=rg(1), searchdirection:=xlPrevious)
If Not where Is Nothing Then
MsgBox "Xuất hiện lầ cuối ở vị trí " & where.Address(0, 0)
Else
MsgBox "không tìm được"
End If
 
Upvote 0
Công thức:
Dùng hàm Lookup, hoặc Match (cse)
tìm trị: =Lookup(2, 1/($a$1:$a$500="trị"), $b1:$b$500)
tìm dòng: {=Match(True, $a$1:$a$500="trị",True)}

VBA:
Nếu đã chép vào mảng rồi thì dò mảng từ dòng cuối ngược trở lên.
Nếu còn nằm trong range thì dùng phương thức Find; dò theo chiều ngược.

For i = Ubound(mang) To Lbound(mang) Step -1
If mang(i) = "trị" Then Exit For
Next i
If i >= Lbound(mang) Then
MsgBox "Xuất hiện lầ cuối ở vị trí " & i
Else
MsgBox "không tìm được"
End If

Set rg = Range("A1:A500")
Set where = rg.Find(what:="trị", after:=rg(1), searchdirection:=xlPrevious)
If Not where Is Nothing Then
MsgBox "Xuất hiện lầ cuối ở vị trí " & where.Address(0, 0)
Else
MsgBox "không tìm được"
End If
Em cảm ơn ạ.
 
Upvote 0
Dữ liệu của em không được sắp xếp ạ. Bác có thể nói rõ hơn giúp em về vấn đề FOR duyệt mảng là như nào không ạ. Vì trong file của em em toàn là For 1 to dong_cuoi thôi ạ. và cứ thế rất nhiều chỗ em đều làm như vậy bảo sao load mãi mới ra ạ
Tôi không hiểu ý bạn. Cho dù có 10000 dòng dữ liệu thì số lần phải thực hiện thao tác "sao chép" là như nhau dù cho dò theo cách của bạn hay dò trong mảng theo befaint. Vd. trong 10000 dòng dữ liệu chỉ có 10 dòng thỏa điều kiện thì chỉ sao chép (kết quả) cho 10 dòng thỏa, dù làm theo cách của bạn hay làm theo cách của befaint. 10 thao tác sao chép là như nhau, không tiết kiệm được. Còn trong 9990 dòng còn lại thì chỉ là kiểm tra điều kiện, không có sao chép gì nên dò trong mảng rất nhanh.
Dò theo kiểu của bạn là đọc từng giá trị từ sheet
Mã:
ma = .Cells(i, "L").Value)
nên sẽ rất chậm. Còn befaint lấy 1 lần từ cột L vào mảng ds_ma
Mã:
ds_ma = .range(col_ma & start_row & ":" & col_ma & last_row).value2
sau đó đọc Mã từ mảng ds_ma
Mã:
vba.ucase$(ds_ma(i,1))
nên sẽ nhanh hơn rất rất nhiều.

Nếu dữ liệu không được sắp xếp thì luôn phải dò từ dòng đầu tới cuối cho dù bạn làm theo befaint hay dùng FIND. FIND thì cũng phải dò từ đầu đến cuối (Do ... Loop) chứ dò "đến nửa chừng" thì làm sao biết đã hết dòng thỏa hay chưa.
Vậy nếu for lặp thì cứ mỗi 1 ô ghi chú nó sẽ lặp từ 1 đến cuối dòng cùng, và có hơn chục nhóm dịch vụ thì nó sẽ lặp lại như thế thêm hơn chục lần ạ.
Mình làm theo cách lặp từng dòng đó thì mỗi 1 mã mất 4 5s gì đó để nhảy xong ạ.
Đây là phần sao chép để tạo kết quả (10 kết quả như tôi ví dụ ở trên). Lâu do bạn đọc từng dữ liệu từ sheet để tạo kết quả. Nếu phần sao chép cũng là đọc từ mảng (chỉ 1 lần đưa vào mảng) thì sẽ nhanh hơn rất nhiều.

Dò như befaint là từ dòng 1 tới dòng cuối. Làm theo bác VetMini là trước tiên xác định dòng cuối thỏa rồi dò từ dòng 1 tới dòng cuối thỏa. Theo cách này thì không dò từ "dòng cuối thỏa" + 1 tới dòng cuối. Nhưng từ "dòng cuối thỏa" + 1 tới dòng cuối chỉ là kiểm tra điều kiện (luôn trả về FALSE), không có sao chép kết quả gì, nên code chạy rất nhanh. Sự tiết kiệm ở đây là không đáng kể. Sự tiết kiệm đáng kể là do duyệt mảng thay cho duyệt sheet, kể cả khi kiểm tra điều kiện và cả khi sao chép dữ liệu để tạo kết quả. Tối ưu là ở đây thôi.

Tất cả mọi bài hiện có chỉ là gợi ý, vd. befaint gợi ý
Mã:
result (j,1)="chang_biet_lay_gi"
Bạn không đính kèm tập tin, thậm chí không có ảnh, chỉ tung 1 đoạn ngắn code thì không ai biết bạn cần sao chép gì vào kết quả. Không ai có thể viết code từ A-Z cho bạn. Kể cả thánh.

Vì thế lần sau hãy đính kèm tập tin và mô tả kỹ nếu muốn người khác cầy hộ từ A đến Z.

Tôi dừng ở đây.
 
Upvote 0
Tôi không hiểu ý bạn. Cho dù có 10000 dòng dữ liệu thì số lần phải thực hiện thao tác "sao chép" là như nhau dù cho dò theo cách của bạn hay dò trong mảng theo befaint. Vd. trong 10000 dòng dữ liệu chỉ có 10 dòng thỏa điều kiện thì chỉ sao chép (kết quả) cho 10 dòng thỏa, dù làm theo cách của bạn hay làm theo cách của befaint. 10 thao tác sao chép là như nhau, không tiết kiệm được. Còn trong 9990 dòng còn lại thì chỉ là kiểm tra điều kiện, không có sao chép gì nên dò trong mảng rất nhanh.
Dò theo kiểu của bạn là đọc từng giá trị từ sheet
Mã:
ma = .Cells(i, "L").Value)
nên sẽ rất chậm. Còn befaint lấy 1 lần từ cột L vào mảng ds_ma
Mã:
ds_ma = .range(col_ma & start_row & ":" & col_ma & last_row).value2
sau đó đọc Mã từ mảng ds_ma
Mã:
vba.ucase$(ds_ma(i,1))
nên sẽ nhanh hơn rất rất nhiều.

Nếu dữ liệu không được sắp xếp thì luôn phải dò từ dòng đầu tới cuối cho dù bạn làm theo befaint hay dùng FIND. FIND thì cũng phải dò từ đầu đến cuối (Do ... Loop) chứ dò "đến nửa chừng" thì làm sao biết đã hết dòng thỏa hay chưa.

Đây là phần sao chép để tạo kết quả (10 kết quả như tôi ví dụ ở trên). Lâu do bạn đọc từng dữ liệu từ sheet để tạo kết quả. Nếu phần sao chép cũng là đọc từ mảng (chỉ 1 lần đưa vào mảng) thì sẽ nhanh hơn rất nhiều.

Dò như befaint là từ dòng 1 tới dòng cuối. Làm theo bác VetMini là trước tiên xác định dòng cuối thỏa rồi dò từ dòng 1 tới dòng cuối thỏa. Theo cách này thì không dò từ "dòng cuối thỏa" + 1 tới dòng cuối. Nhưng từ "dòng cuối thỏa" + 1 tới dòng cuối chỉ là kiểm tra điều kiện (luôn trả về FALSE), không có sao chép kết quả gì, nên code chạy rất nhanh. Sự tiết kiệm ở đây là không đáng kể. Sự tiết kiệm đáng kể là do duyệt mảng thay cho duyệt sheet, kể cả khi kiểm tra điều kiện và cả khi sao chép dữ liệu để tạo kết quả. Tối ưu là ở đây thôi.

Tất cả mọi bài hiện có chỉ là gợi ý, vd. befaint gợi ý
Mã:
result (j,1)="chang_biet_lay_gi"
Bạn không đính kèm tập tin, thậm chí không có ảnh, chỉ tung 1 đoạn ngắn code thì không ai biết bạn cần sao chép gì vào kết quả. Không ai có thể viết code từ A-Z cho bạn. Kể cả thánh.

Vì thế lần sau hãy đính kèm tập tin và mô tả kỹ nếu muốn người khác cầy hộ từ A đến Z.

Tôi dừng ở đây.

Vâng. Em cảm ơn nhiều ạ.
Lần sau em sẽ chi tiết và kèm theo file ạ
 
Upvote 0
Web KT

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

Back
Top Bottom