Mình cần các bác giúp đỡ lấy những tên xuất hiện > 3 lần trong 1 ô theo như file đính kèm.
Mình cần các bác giúp đỡ lấy những tên xuất hiện > 3 lần trong 1 ô theo như file đính kèm.
Ý của mình là những tên nào xuất hiện trong chuỗi từ 3 lần trở lên thì sẽ lấy ra.
Ví dụ : sơn, hải, lâm, sơn, hải, sơn, hải, lâm, đô ==> kết quả sẽ lấy ra: sơn,hải
Repeat3(E6)
hoặc
RepeatN(E6, 3)
Function Repeat3(ByVal cell_str As String) As String
Dim Arr() As String, dic As Object, s As String, index As Long, tmp
Arr = Split(cell_str, ",")
Set dic = CreateObject("Scripting.Dictionary")
For index = 0 To UBound(Arr)
s = Trim(Arr(index))
If Not dic.exists(s) Then
dic.Add s, index * 1000 + 1
Else
dic.Item(s) = dic.Item(s) + 1
End If
Next index
s = ""
For Each tmp In dic.items
If tmp Mod 1000 >= 3 Then s = s & Arr(tmp \ 1000) & ", "
Next tmp
Set dic = Nothing
Repeat3 = Left(s, Len(s) - 2)
End Function
Function RepeatN(ByVal cell_str As String, ByVal repeat_count As Long) As String
Dim Arr() As String, dic As Object, s As String, index As Long, tmp
Arr = Split(cell_str, ",")
Set dic = CreateObject("Scripting.Dictionary")
For index = 0 To UBound(Arr)
s = Trim(Arr(index))
If s <> "" Then
If Not dic.exists(s) Then
dic.Add s, index * 1000 + 1
Else
dic.Item(s) = dic.Item(s) + 1
End If
End If
Next index
s = ""
For Each tmp In dic.items
If tmp Mod 1000 >= repeat_count Then s = s & Arr(tmp \ 1000) & ", "
Next tmp
Set dic = Nothing
RepeatN = Left(s, Len(s) - 2)
End Function
Ý của mình là những tên nào xuất hiện trong chuỗi từ 3 lần trở lên thì sẽ lấy ra.
Ví dụ : sơn, hải, lâm, sơn, hải, sơn, hải, lâm, đô ==> kết quả sẽ lấy ra: sơn,hải
Function DemTen(rng As Range, n As Byte)
Dim ch As String, tam(), kq(), d As Object
ch = rng.Value
ReDim tam(1 To Len(ch), 1 To 2)
Set d = CreateObject("Scripting.Dictionary")
pos = 1
For i = 1 To Len(ch)
If Mid(ch, i, 1) = "," Then
npos = i
If Not d.Exists(Trim(Replace(Mid(ch, pos, npos - pos), ",", " "))) Then
k = k + 1
d.Add Trim(Replace(Mid(ch, pos, npos - pos), ",", " ")), k
tam(k, 1) = Trim(Replace(Mid(ch, pos, npos - pos), ",", " "))
tam(k, 2) = 1
Else
tam(d.Item(Trim(Replace(Mid(ch, pos, npos - pos), ",", " "))), 2) = tam(d.Item(Trim(Replace(Mid(ch, pos, npos - pos), ",", " "))), 2) + 1
End If
pos = npos + 1
End If
Next i
For i = 1 To UBound(tam)
If tam(i, 2) >= n Then
l = l + 1
ReDim Preserve kq(1 To l)
kq(l) = tam(i, 1)
End If
Next i
DemTen = Join(kq, ",")
Set d = Nothing
End Function
=DemTen(E6,3)
Function DupList(ByVal cllStr As String, ByVal dupNumAs Integer) As String
[COLOR=#008000]' hàm tìm những chuỗi trong ô được lặp lại dupNum lần hoặc nhiều hơn
' thay vì dùng phương pháp hữu hiệu nhất là dictionary thì hàm này chơi kiểu bằng cách dùng mảng
[/COLOR]Dim s As Variant, s1 As Variant
Dim cnt As Integer
Dim aL As Object
Set aL = CreateObject("System.Collections.ArrayList") [COLOR=#008000]' lười biếng viết hàm sort nên dùng collection[/COLOR]
For Each s In Split(cllStr, ",")
If s <> "" Then aL.Add Trim(s)
Next s
aL.Sort
[COLOR=#008000]' sau khi có mảng đã sắp xếp, chỉ việc đếm
[/COLOR]cnt = 0
s1 = ChrW(32768) [COLOR=#008000]' trị gì cũng được, miễn là không thể tìm thấy trong chuõi[/COLOR]
For Each s In aL
If s <> s1 Then
If cnt >= dupNum Then DupList = DupList & ", " & s1
s1 = s
cnt = 1
Else
cnt = cnt + 1
End If
Next s
DupList = Mid(DupList, 3, Len(DupList))
End Function
Mình cần các bác giúp đỡ lấy những tên xuất hiện > 3 lần trong 1 ô theo như file đính kèm.
Function loc(cell, n)
Set d = CreateObject("scripting.dictionary")
For Each e In Split(Replace(cell, " ", ""), ",")
If e <> "" And Not d.exists(e) Then If (Len(cell) _
- Len(Replace(cell, e, ""))) / Len(e) >= n Then d.Add e, ""
Next
loc = Join(d.keys, ", ")
End Function
mình sức khoẻ yếu nên chỉ viết được có 1 vòng lặp, bạn thử coi chạy có nổi không ?
Mã:Function loc(cell, n) Set d = CreateObject("scripting.dictionary") For Each e In Split(Replace(cell, " ", ""), ",") If e <> "" And Not d.exists(e) Then If (Len(cell) _ - Len(Replace(cell, e, ""))) / Len(e) >= n Then d.Add e, "" Next loc = Join(d.keys, ", ") End Function
Mình nghĩ bài này dùng Replace cũng hay, nhưng Replace & InStr cũng dễ bị "tèo" lắm, có nhiều cách viết, không biết code này có vướng chỗ nào hông nữa:Mình cần các bác giúp đỡ lấy những tên xuất hiện > 3 lần trong 1 ô theo như file đính kèm.
Public Function Trung(Cll, iSo) As String
Dim A, B, C, Tam, Kq
Cll = Replace(Replace(Cll, " ", ""), ",", "@") & "@"
A = Len(Cll)
Do While A > 0
B = InStr(Cll, "@")
Tam = Left(Cll, B - 1)
Cll = Replace(Cll, Left(Cll, B), "")
C = Len(Cll)
If (A - C) / B >= iSo Then Kq = Kq & ", " & Tam
A = C
Loop
If Len(Kq) Then Trung = Right(Kq, Len(Kq) - 2)
End Function
Mình nghĩ bài này dùng Replace cũng hay, nhưng Replace & InStr cũng dễ bị "tèo" lắm, có nhiều cách viết, không biết code này có vướng chỗ nào hông nữa:
Cách này dùng lấy duy nhất cũng có vẻ ổnMã:Public Function Trung(Cll, iSo) As String Dim A, B, C, Tam, Kq Cll = Replace(Replace(Cll, " ", ""), ",", "@") & "@" A = Len(Cll) Do While A > 0 B = InStr(Cll, "@") Tam = Left(Cll, B - 1) Cll = Replace(Cll, Left(Cll, B), "") C = Len(Cll) If (A - C) / B >= iSo Then Kq = Kq & ", " & Tam A = C Loop If Len(Kq) Then Trung = Right(Kq, Len(Kq) - 2) End Function
Híc
Bác Bill cho sẵn cái Dic rồi mà không dùng thì cũng phíNếu vẫn dùng Dictionary và 1 VÒNG LẬP thì.. sao ta? (không dùng Replace hay InStr)
Em "cảm giác" rằng dùng 1 VÒNG LẬP vẫn ra nhưng... lười
Ẹc... Ẹc...
Function Loc(cell As Range, MX As Byte)
Dim tmp, i, StrRes
tmp = Split(cell, ",")
With CreateObject("scripting.dictionary")
For i = LBound(tmp) To UBound(tmp)
If Not .exists(Trim(tmp(i))) Then
.Add Trim(tmp(i)), 1
Else
.Item(Trim(tmp(i))) = .Item(Trim(tmp(i))) + 1
If .Item(Trim(tmp(i))) = MX Then
StrRes = StrRes & Trim(tmp(i)) & ","
End If
End If
Next
End With
If Len(StrRes) Then
Loc = Left(StrRes, Len(StrRes) - 1)
Else
Loc = ""
End If
End Function
Thì "Dictionary và 1 VÒNG LẬP" ra ......là cái chắc rồi. Tách nó ra, cho chạy từ đầu tới cuối, dùng em "Đít- to" đếm nó, "thằng" nào bằng điều kiện thì gán vào kết quả, nhưng "chơi" kiểu này phải......chạy hếtNếu vẫn dùng Dictionary và 1 VÒNG LẬP thì.. sao ta? (không dùng Replace hay InStr)
Em "cảm giác" rằng dùng 1 VÒNG LẬP vẫn ra nhưng... lười
Ẹc... Ẹc...
Bác Bill cho sẵn cái Dic rồi mà không dùng thì cũng phí
Em tạm code thế này, mặc định là các tên cách nhau bởi dấu phẩy. Nếu có thêm gì khác thì chỉnh lại xíu
Chắc là thêm cái Replace ngay lúc Split
PHP:Function Loc(cell As Range, MX As Byte) Dim tmp, i, StrRes tmp = Split(cell, ",") With CreateObject("scripting.dictionary") For i = LBound(tmp) To UBound(tmp) If Not .exists(Trim(tmp(i))) Then .Add Trim(tmp(i)), 1 Else .Item(Trim(tmp(i))) = .Item(Trim(tmp(i))) + 1 If .Item(Trim(tmp(i))) = MX Then StrRes = StrRes & Trim(tmp(i)) & "," End If End If Next End With If Len(StrRes) Then Loc = Left(StrRes, Len(StrRes) - 1) Else Loc = "" End If End Function
Mình nghĩ bài này dùng Replace cũng hay, nhưng Replace & InStr cũng dễ bị "tèo" lắm, có nhiều cách viết, không biết code này có vướng chỗ nào hông nữa:
Cách này dùng lấy duy nhất cũng có vẻ ổnMã:Public Function Trung(Cll, iSo) As String Dim A, B, C, Tam, Kq Cll = Replace(Replace(Cll, " ", ""), ",", "@") & "@" A = Len(Cll) Do While A > 0 B = InStr(Cll, "@") Tam = Left(Cll, B - 1) Cll = Replace(Cll, Left(Cll, B), "") C = Len(Cll) If (A - C) / B >= iSo Then Kq = Kq & ", " & Tam A = C Loop If Len(Kq) Then Trung = Right(Kq, Len(Kq) - 2) End Function
Híc
Function RptLst(ByVal cllStr As String, ByVal rptNum As Integer) As String
[COLOR=#008000]' tìm trong chuõi những cụm từ được lặp lại ít nhất rptNum lần
' các cụm từ cách nhau bởi dấu phẩy. Hàm này cũng chuẩn hoá cụm từ kết quả (gom các dấu cách lại thành 1)
[/COLOR]Dim cllStrNu As String, s As Variant
[COLOR=#008000]' chuẩn hoá chuỗi, đồng thời nhét các dấu ngăn cụm từ vào
[/COLOR]cllStr = "|" & Replace(Replace(Replace( _
Application.Trim(cllStr), ", ", ","), " ,", ","), ",", "|,|") & "|"
RptLst = ""
For Each s In Split(cllStr, ",")
cllStrNu = Replace(cllStr, s, "")
If (Len(cllStr) - Len(cllStrNu)) >= Len(s) * rptNum Then _
RptLst = RptLst & IIf(RptLst = "", "", ", ") & s
cllStr = cllStrNu
Next s
RptLst = Replace(Replace(RptLst, ", ||", ""), "|", "")[COLOR=#008000] ' loại các dấu ngăn cụm từ[/COLOR]
End Function
[COLOR=#008000]' lưu ý là trong code trên, tôi cố tình đưa ra 2 kiểu mới:
' 1: so sánh số lần xuất hiện bằng cách nhân thay vì chia
' 2: dùng hàm IIF để xác định dấu phẩy khi ghép cụm từ[/COLOR]
Trong đề bài không có "cụm từ" nên không quan tâm đến "cụm từ"Code này vẫn dùng kiểu đổi " " thành "" cho nên "Lan Anh" cho ra kết quả là "LanAnh"
Trước đó tôi đã có ý định dùng phương "đêm bằng cách loại trừ" (hàm replace + len) nhưng bị vướng cái chỗ "Trim". Chưa biết cách nào trim được cụm từ mà không qua vòng lặp cho nên thôi.
......
** Theo thiển ý thì có thiếu giống gì cách để giảm số vòng lặp. Vấn đề là có xứng đáng đặt tầm quan trọng như thế hay không.
Function ttt(ByVal cllStr As String, ByVal rptNum As Integer) As String
[COLOR=#008000]' lưu ý là bài này dùng # làm ký tự ngăn chuỗi, bởi vì | có ý nghĩa đặc biệt trong RegEx
[/COLOR]Dim rx As Object, s As Variant
Set rx = CreateObject("VBScript.RegExp")
rx.IgnoreCase = False
rx.Global = True
rx.Pattern = " *# *"[COLOR=#008000] ' dấu ngăn cụm từ và tất cả các dấu cách chung quanh nó[/COLOR]
cllStr = rx.Replace("#" & Replace(cllStr, ",", "#,#") & "#", "#") [COLOR=#008000]' loại tất cả các dấu cách quanh dấu ngăn cụm từ[/COLOR]
For Each s In Split(cllStr, ",")
rx.Pattern = s
If rx.test(cllStr) Then
If rx.Execute(cllStr).Count >= rptNum Then ttt = ttt & ", " & s[COLOR=#008000] ' đạt số lần xuất hiện[/COLOR]
cllStr = rx.Replace(cllStr, "")[COLOR=#008000] ' xoá cụm từ này đi[/COLOR]
End If
Next s
rx.Pattern = "(^, )|(##, )|(, ##)|(#)"[COLOR=#008000] ' dấu ", " đầu chuỗi, hai dấu ## liên tiếp, và dấu # đơn độc[/COLOR]
ttt = rx.Replace(ttt, "")[COLOR=#008000] ' xoá hết các dấu trong mẫu[/COLOR]
End Function
Lỡ bày trò ăn món lạ, phở, mì, cơm tấm xong rồi, chơi thử "cháo lòng" luôn:
Bài này dùng RegEx
Function RepeatN(ByVal cell_str As String, ByVal repeat_count As Long, _
Optional ByVal phan_biet_hoa_thuong As Boolean = False) As String
Dim re As Object, s As String, item
cell_str = Replace(cell_str, " ", "")
Set re = CreateObject("VBScript.RegExp")
re.Global = True
re.ignorecase = Not phan_biet_hoa_thuong
For Each item In Split(cell_str, ",")
If item <> "" Then
re.Pattern = "(?:^|,)" & item & "(?=(?:,|$))"
If re.Execute(cell_str).Count >= repeat_count Then
s = s & item & ", "
cell_str = re.Replace(cell_str, "")
End If
End If
Next item
Set re = Nothing
If s <> "" Then RepeatN = Left(s, Len(s) - 2)
End Function