Nhờ bổ sung code VBA. (2 người xem)

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

ngoclinh28061991

Thành viên mới
Tham gia
24/9/13
Bài viết
31
Được thích
1
Em có file dữ liệu như tệp đính kèm (đâylà file dung lượng nhỏ, file này do phần mềm xuất ra). Em muốn sắp xếp dữ liệu ởcột B và C thành các nhóm riêng rẽ ra các cột khác nằm bên phải dữ liệu gốc (cộtA ko quan tâm). sau đó áp dụng công thức: =COUNTIF(G$1:G$"&j;”>=”& G1)/j để tính ra phần trăm (với j là biến, j là số dòng dữ liệu của các sốliệu giống nhau, ví dụ tệp đính kèm có 72 dòng dữ liệu 140.05 thì j = 72 ).

Đoạn code sau được anh quanghai1969 viết, đã chạy đúng yêu cầu:

PHP:
Sub ReArrange()
Dim Data(), Res(), i, j, k, item, kk, Des As Range
Set Des = [D3]
Data = Range([B3], [C1000000].End(3)).Value
With CreateObject("scripting.dictionary")
   For i = 1 To UBound(Data)
      If Not .exists(Data(i, 1)) Then
         .Add Data(i, 1), ""
      End If
   Next
   ReDim Res(1 To 65536, 1 To 3 * .Count)
   For Each item In .keys
      For i = 1 To UBound(Data)
         If item = Data(i, 1) Then
            k = k + 1
            Res(k, j + 1) = Data(i, 1)
            Res(k, j + 2) = Data(i, 2)
         End If
      Next
      For i = 1 To k
         Res(i, j + 3) = "=Countif(R3C[-1]:R" & k + 2 & "C[-1],"">=""&RC[-1])/" & k + 2
      Next
      Des.Offset(, j + 2).Resize(k).Style = "Percent"
      kk = k
      k = 0
      j = j + 3
   Next
End With
Des.Resize(kk, UBound(Res, 2)) = Res
End Sub
Khi dữ liệu lớn khoảng 300.000 dòng thì máy tính của em chạy tới khoảng 15 phút mới xong. Do chưa có nhiều kiến thức về scripting.dictionary nên em không thể tự bổ sung code được.Nên em nhờ mọi người giúp em bổ sung code sao cho ở cột tính ra %, khi số phần trăm tính ra nằm trong khoảng 20%-22% thì dừng lại, không cần tính đến dòng cuối cùng. Như vậy, khi dữ liệu lớn code sẽ chạy nhanh hơn.
 

File đính kèm

Em có file dữ liệu như tệp đính kèm (đâylà file dung lượng nhỏ, file này do phần mềm xuất ra). Em muốn sắp xếp dữ liệu ởcột B và C thành các nhóm riêng rẽ ra các cột khác nằm bên phải dữ liệu gốc (cộtA ko quan tâm). sau đó áp dụng công thức: =COUNTIF(G$1:G$"&j;”>=”& G1)/j để tính ra phần trăm (với j là biến, j là số dòng dữ liệu của các sốliệu giống nhau, ví dụ tệp đính kèm có 72 dòng dữ liệu 140.05 thì j = 72 ).

Đoạn code sau được anh quanghai1969 viết, đã chạy đúng yêu cầu:

PHP:
Sub ReArrange()
Dim Data(), Res(), i, j, k, item, kk, Des As Range
Set Des = [D3]
Data = Range([B3], [C1000000].End(3)).Value
With CreateObject("scripting.dictionary")
   For i = 1 To UBound(Data)
      If Not .exists(Data(i, 1)) Then
         .Add Data(i, 1), ""
      End If
   Next
   ReDim Res(1 To 65536, 1 To 3 * .Count)
   For Each item In .keys
      For i = 1 To UBound(Data)
         If item = Data(i, 1) Then
            k = k + 1
            Res(k, j + 1) = Data(i, 1)
            Res(k, j + 2) = Data(i, 2)
         End If
      Next
      For i = 1 To k
         Res(i, j + 3) = "=Countif(R3C[-1]:R" & k + 2 & "C[-1],"">=""&RC[-1])/" & k + 2
      Next
      Des.Offset(, j + 2).Resize(k).Style = "Percent"
      kk = k
      k = 0
      j = j + 3
   Next
End With
Des.Resize(kk, UBound(Res, 2)) = Res
End Sub

Bạn nói "chạy đúng" nhưng theo miêu tả và nhìn vào code tôi thấy công thức sai. Vì nếu có 72 dòng với 140.05 thì k = 72 nên k + 2 = 74 nên có vd. F13 =COUNTIF(E$3:E$74;">="&E13)/
74. Trong khi đó theo miêu tả thì phải có F13 =COUNTIF(E$3:E$74;">="&E13)/72

Ngoài ra nếu có 72 số 140,05 (k = 72), 98 số 148 (k = 98), 3 số 152 (k = 3) ... thì tính sao?
Khi dữ liệu lớn khoảng 300.000 dòng thì máy tính của em chạy tới khoảng 15 phút mới xong. Do chưa có nhiều kiến thức về scripting.dictionary nên em không thể tự bổ sung code được.Nên em nhờ mọi người giúp em bổ sung code sao cho ở cột tính ra %, khi số phần trăm tính ra nằm trong khoảng 20%-22% thì dừng lại, không cần tính đến dòng cuối cùng. Như vậy, khi dữ liệu lớn code sẽ chạy nhanh hơn.

Ta thử bỏ công thức xem sao. Tôi mới nhìn qua nên có thể còn lâu hơn 15 phút đấy.


Mã:
Sub hichic()
Dim Data(), dic As Object, item_count() As Long, result() As Double, destRng As Range
Dim index As Long, k As Long, item As Double, max_row As Long, r As Long, r1 As Long, c As 

Long, count As Long, curr_index As Long

    Set destRng = [D3]
    Data = Range([B3], [C1000000].End(xlUp)).Value
    
    Set dic = CreateObject("scripting.dictionary")
    For index = 1 To UBound(Data)
        If Not dic.exists(Data(index, 1)) Then
            count = count + 1
            curr_index = count
            dic.Add Data(index, 1), curr_index
            ReDim Preserve result(1 To 65536, 1 To 3 * curr_index)
            ReDim Preserve item_count(1 To curr_index)
            item_count(curr_index) = 1
        Else
            curr_index = dic.item(Data(index, 1))
            item_count(curr_index) = item_count(curr_index) + 1
        End If
        c = (curr_index - 1) * 3 + 1
        result(item_count(curr_index), c) = Data(index, 1)
        result(item_count(curr_index), c + 1) = Data(index, 2)
    Next
    
    For index = 1 To count
        c = index * 3 - 1
        destRng.Offset(, c).Resize(item_count(index)).Style = "Percent"
        If max_row < item_count(index) Then max_row = item_count(index)
        For r = 1 To item_count(index)
            k = 0
            item = result(r, c)
            For r1 = 1 To item_count(index)
                If result(r1, c) >= item Then k = k + 1
            Next
            result(r, c + 1) = k / item_count(index)
        Next
    Next
    destRng.Resize(max_row, 3 * count).Value = result
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Em có file dữ liệu như tệp đính kèm (đâylà file dung lượng nhỏ, file này do phần mềm xuất ra). Em muốn sắp xếp dữ liệu ởcột B và C thành các nhóm riêng rẽ ra các cột khác nằm bên phải dữ liệu gốc (cộtA ko quan tâm). sau đó áp dụng công thức: =COUNTIF(G$1:G$"&j;”>=”& G1)/j để tính ra phần trăm (với j là biến, j là số dòng dữ liệu của các sốliệu giống nhau, ví dụ tệp đính kèm có 72 dòng dữ liệu 140.05 thì j = 72 ).

Đoạn code sau được anh quanghai1969 viết, đã chạy đúng yêu cầu:

PHP:
Sub ReArrange()
Dim Data(), Res(), i, j, k, item, kk, Des As Range
Set Des = [D3]
Data = Range([B3], [C1000000].End(3)).Value
With CreateObject("scripting.dictionary")
   For i = 1 To UBound(Data)
      If Not .exists(Data(i, 1)) Then
         .Add Data(i, 1), ""
      End If
   Next
   ReDim Res(1 To 65536, 1 To 3 * .Count)
   For Each item In .keys
      For i = 1 To UBound(Data)
         If item = Data(i, 1) Then
            k = k + 1
            Res(k, j + 1) = Data(i, 1)
            Res(k, j + 2) = Data(i, 2)
         End If
      Next
      For i = 1 To k
         Res(i, j + 3) = "=Countif(R3C[-1]:R" & k + 2 & "C[-1],"">=""&RC[-1])/" & k + 2
      Next
      Des.Offset(, j + 2).Resize(k).Style = "Percent"
      kk = k
      k = 0
      j = j + 3
   Next
End With
Des.Resize(kk, UBound(Res, 2)) = Res
End Sub
Khi dữ liệu lớn khoảng 300.000 dòng thì máy tính của em chạy tới khoảng 15 phút mới xong. Do chưa có nhiều kiến thức về scripting.dictionary nên em không thể tự bổ sung code được.Nên em nhờ mọi người giúp em bổ sung code sao cho ở cột tính ra %, khi số phần trăm tính ra nằm trong khoảng 20%-22% thì dừng lại, không cần tính đến dòng cuối cùng. Như vậy, khi dữ liệu lớn code sẽ chạy nhanh hơn.

Lúc trước đã nói rồi, cái công thức countif đó sẽ làm máy chạy không nổi mà không chịu.
Nếu bỏ công thức chỉ lấy giá trị, thì với 100 000 dòng chạy chưa tới 5s. Nghe khó tin nhỉ, nhưng mình có thể đấy.
 
Upvote 0
Lúc trước đã nói rồi, cái công thức countif đó sẽ làm máy chạy không nổi mà không chịu.

Đúng là cái tính phần trăm là thủ phạm. Nếu viết code để tính phần trăm thì cũng tùy dữ liệu. Nếu 300 000 dòng mà chỉ có 5 giá trị khác nhau ở cột B thì trung bình mỗi giá trị lặp 60 000 lần. Lúc đó thì code ở bài #2 chạy tới ngày tận thế. Nhưng nếu là 5000 giá trị khác nhau và trung bình mỗi giá trị lặp lại 60 lần thì code chạy nhanh hơn rất rất nhiều.

Nói chung phải viết code khác.
 
Upvote 0
Em có file dữ liệu như tệp đính kèm (đâylà file dung lượng nhỏ, file này do phần mềm xuất ra). Em muốn sắp xếp dữ liệu ởcột B và C thành các nhóm riêng rẽ ra các cột khác nằm bên phải dữ liệu gốc (cộtA ko quan tâm). sau đó áp dụng công thức: =COUNTIF(G$1:G$"&j;”>=”& G1)/j để tính ra phần trăm (với j là biến, j là số dòng dữ liệu của các sốliệu giống nhau, ví dụ tệp đính kèm có 72 dòng dữ liệu 140.05 thì j = 72 ).


Tôi viết lại bài #2 nhưng không có dữ liệu "khủng" để test. Tất nhiên tôi có thể lấy dữ liệu 360 dòng của bạn rồi nhân bản lên 1000 lần nhưng như thế dữ liệu "giả tạo" quá.

Bạn hãy test với dữ liệu "khủng" và cho biết kết quả.

Sau khi test xong (Sub hichic) thì xóa các dòng đỏ

Chú ý: code viết cho phiên bản 32-bit

Mã:
[COLOR=#ff0000]Private Declare Function GetTickCount Lib "kernel32.dll" () As Long[/COLOR]
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef source As Any, ByVal Length As Long)

Sub hichic()
Dim Data(), dic As Object, item_count() As Long, result() As Double, tmp() As Double, destRng As Range, keys, curr_value As Double
Dim index As Long, k As Long, item As Double, max_row As Long, r As Long, r1 As Long, c As Long, count As Long, curr_index As Long
[COLOR=#ff0000]Dim t As Double
    t = GetTickCount[/COLOR]
    
    Set destRng = [D3]
    Data = Range([B3], [C1000000].End(xlUp)).Value
    
    Set dic = CreateObject("scripting.dictionary")
    For index = 1 To UBound(Data)
        If Not dic.exists(Data(index, 1)) Then
            count = count + 1
            curr_index = count
            dic.Add Data(index, 1), curr_index
            ReDim Preserve result(1 To 65536, 1 To 3 * curr_index)
            ReDim Preserve item_count(1 To curr_index)
            item_count(curr_index) = 1
        Else
            curr_index = dic.item(Data(index, 1))
            item_count(curr_index) = item_count(curr_index) + 1
        End If
        c = (curr_index - 1) * 3 + 1
        result(item_count(curr_index), c) = Data(index, 1)
        result(item_count(curr_index), c + 1) = Data(index, 2)
    Next
    
    For index = 1 To count
        c = index * 3 - 1
        destRng.Offset(, c).Resize(item_count(index)).Style = "Percent"
        If max_row < item_count(index) Then max_row = item_count(index)
        ReDim tmp(1 To item_count(index))
        CopyMemory ByVal VarPtr(tmp(1)), ByVal VarPtr(result(1, c)), UBound(tmp) * 8
        QuickSort1DArray tmp, 1, item_count(index), False
        dic.RemoveAll
        For r = 1 To item_count(index)
            If Not dic.exists(tmp(r)) Then
                dic.Add tmp(r), 1
            Else
                dic.item(tmp(r)) = dic.item(tmp(r)) + 1
            End If
        Next
        keys = dic.keys
        For r = 1 To item_count(index)
            k = 0
            item = result(r, c)
            For r1 = 0 To dic.count - 1
                curr_value = keys(r1)
                If curr_value >= item Then
                    k = k + dic.item(curr_value)
                Else
                    Exit For
                End If
            Next
            result(r, c + 1) = k / item_count(index)
        Next
    Next
    destRng.Resize(max_row, 3 * count).Value = result
    [COLOR=#ff0000]MsgBox (GetTickCount - t) / 1000[/COLOR]
End Sub

Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
'    Arr laĚ maŇng câĚn săěp xęěp
'    sortAtoZ xaěc điňnh caěch săěp xęěp tăng hay giaŇm
'    iLo laĚ câňn dýőěi cuŇa maŇng Arr, iHi laĚ câňn tręn cuŇa maŇng Arr
Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s

    Do
        Lo = iLo
        Hi = iHi
        
        iMid = Arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While Arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While Arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (Arr(Lo) > Arr(Hi))
                Else
                    DoChange = (Arr(Lo) < Arr(Hi))
                End If
                If DoChange Then
                    s = Arr(Lo)
                    Arr(Lo) = Arr(Hi)
                    Arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then QuickSort1DArray Arr, iLo, Hi, sortAtoZ
        iLo = Lo
    Loop Until Lo >= iHi
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi viết lại bài #2 nhưng không có dữ liệu "khủng" để test. Tất nhiên tôi có thể lấy dữ liệu 360 dòng của bạn rồi nhân bản lên 1000 lần nhưng như thế dữ liệu "giả tạo" quá.
Anh sẽ thẩn thờ với tốc độ theo kiểu dã man của em
PHP:
Sub ReArrange2()
On Error Resume Next
Dim Data As Range, D2 As Object, D1 As Object, Sarr(), DArr(), Res()
Dim i As Long, j As Long, tmp2 As String, k  As Long
Dim n  As Long, kk As Long, tmp As String, key
Set D1 = CreateObject("scripting.dictionary")
Set D2 = CreateObject("scripting.dictionary")
Set Data = Range([A3], [C1000000].End(3))
Data.Sort [B2], 2, [C2], , 2
Sarr = Data.Offset(, 1).Value
For i = 1 To UBound(Sarr)
   tmp = Sarr(i, 1) & Sarr(i, 2)
   tmp2 = Sarr(i - 1, 1) & Sarr(i - 1, 2)
   n = D1.item(tmp2)
   If Sarr(i - 1, 1) <> Sarr(i, 1) Then n = 0
   If Not D1.exists(tmp) Then
      D1.Add tmp, 1 + n
   Else
      D1.item(tmp) = D1.item(tmp) + 1
   End If
   If Not D2.exists(Sarr(i, 1)) Then
      D2.Add Sarr(i, 1), 1
   Else
      D2.item(Sarr(i, 1)) = D2.item(Sarr(i, 1)) + 1
   End If
Next
ReDim DArr(1 To 65536, 1 To D2.count * 3)
key = D2.keys
i = 1
For n = 3 To (UBound(key) + 1) * 3 Step 3
   Do
      tmp = Sarr(i, 1) & Sarr(i, 2)
      Sarr(i, 3) = D1.item(tmp) / D2.item(Sarr(i, 1))
      k = k + 1
      DArr(k, n - 2) = Sarr(i, 1)
      DArr(k, n - 1) = Sarr(i, 2)
      DArr(k, n) = Sarr(i, 3)
      i = i + 1
   Loop Until Sarr(i, 1) <> Sarr(i - 1, 1)
   kk = k
   k = 0
Next
[D3].Resize(kk, UBound(DArr, 2)) = DArr
End Sub
 
Upvote 0
Anh sẽ thẩn thờ với tốc độ theo kiểu dã man của em
PHP:
[/QUOTE]

Kết quả chưa biết nhưng đúng là nhanh chóng mặt.
Nhưng tại sao sau khi chạy code thì dữ liệu trong A, B, C bị sắp xếp? Nếu buộc phải giữ nguyên A, B, C thì phải sửa lại.

Đúng là sort dữ liệu gốc là nhanh nhất. Tôi không biết có được phép thay đổi dữ liệu gốc hay không nên không sort dữ liệu gốc.
 
Lần chỉnh sửa cuối:
Upvote 0
Kết quả chưa biết nhưng đúng là nhanh chóng mặt.
Nhưng tại sao sau khi chạy code thì dữ liệu trong A, B, C bị sắp xếp? Nếu buộc phải giữ nguyên A, B, C thì phải sửa lại.

Đúng là sort dữ liệu gốc là nhanh nhất. Tôi không biết có được phép thay đổi dữ liệu gốc hay không nên không sort dữ liệu gốc.
Nếu không cho thì sort xong mình trả lại.
Cũng bon chen đua tốc độ thử xem :D
PHP:
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
PHP:
Sub ThongKe()
Dim t As Double
    t = GetTickCount
Dim Result As Variant, Data As Variant, Rng As Range, i As Long, iDef As Long, iSec As Long, nSec As Long, MaxDef As Long
Set Rng = Range([A2], [C1048576].End(xlUp))
Result = Rng.Value
Rng.Sort Key1:=[B2], Order1:=xlAscending, Key2:=[C2], Order2:=xlAscending, Header:=xlYes 'xlDescending
Data = Rng.Offset(, 1).Resize(, 2).Value: Rng.Value = Result
Set Rng = Nothing: Erase Result
ReDim Preserve Data(1 To UBound(Data, 1), 1 To 4)
iDef = 1: iSec = 1: nSec = 1
For i = UBound(Data, 1) - 1 To 1 Step -1
    If Data(i, 1) <> Data(i + 1, 1) Then
        Data(i + 1, 3) = iDef
        Data(i + 1, 4) = iSec
        If iSec > MaxDef Then MaxDef = iSec
        iDef = 1: iSec = 1: nSec = nSec + 1
    ElseIf Data(i, 2) <> Data(i + 1, 2) Then
        Data(i + 1, 3) = iDef
        iDef = iDef + 1: iSec = iSec + 1
    Else
        iDef = iDef + 1: iSec = iSec + 1
    End If
Next
ReDim Result(1 To MaxDef, 1 To nSec * 3)
nSec = 0
Dim tam As Long
For i = 2 To UBound(Data, 1)
    If Data(i, 4) <> 0 Then
        iDef = 1: nSec = nSec + 3
        iSec = Data(i, 4)
    Else
        iDef = iDef + 1
    End If
'% giam dan
'    Result(iDef, nSec - 2) = Data(i, 1)
'    Result(iDef, nSec - 1) = Data(i, 2)
'    If Data(i, 3) <> 0 Then
'        Result(iDef, nSec) = Data(i, 3) / iSec * 100 & "%"
'    Else
'        Result(iDef, nSec) = Result(iDef - 1, nSec)
'    End If
'% tang dan
    Result(iSec - iDef + 1, nSec - 2) = Data(i, 1)
    Result(iSec - iDef + 1, nSec - 1) = Data(i, 2)
    If Data(i, 3) <> 0 Then
        Result(iSec - iDef + 1, nSec) = Data(i, 3) / iSec * 100 & "%"
    Else
        Result(iSec - iDef + 1, nSec) = Result(iSec - iDef + 2, nSec)
    End If
Next
[D3].Resize(MaxDef, nSec).Value = Result
MsgBox (GetTickCount - t) / 1000
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Kết quả chưa biết nhưng đúng là nhanh chóng mặt.
Nhưng tại sao sau khi chạy code thì dữ liệu trong A, B, C bị sắp xếp? Nếu buộc phải giữ nguyên A, B, C thì phải sửa lại.

Đúng là sort dữ liệu gốc là nhanh nhất. Tôi không biết có được phép thay đổi dữ liệu gốc hay không nên không sort dữ liệu gốc.
Thật ra em code dựa trên nền ý tưởng của anh đấy. Anh xây sẵn hết rồi, em chỉ chà láng thêm miếng.
Em có nghĩ đến việc trả dữ liệu gốc về nguyên thuỷ rồi. Điều này không khó, chỉ cần em tạo thêm 1 mảng lưu dữ liệu gốc, sau khi xử lý em đập mảng đó về chỗ cũ là xong.
Nhưng vì câu like nên cứ để vậy.
 
Upvote 0
Chủ thớt không trả lời cho bài #2 cho nên tôi không biết là việc công thức tính sai có phải hay không.

Nếu phải thì vấn đề tốc độ chỉ là phụ. Chuyện "kết quả sai mà không hay" mới là chuyện chính. Nếu code ban đầu chạy vèo vèo thì có lẽ chủ thớt không hề biết là mẫu số của mình bị hơi lệch một chút.
Chạy code chỉ trong vòng 1/10 giây nhưng khám phá chỗ sai mất vài ngày? Tôi thà chạy nửa ngày nhưng thấy chỗ sai trong vòng 15 phút.
 
Upvote 0
Chủ thớt không trả lời cho bài #2 cho nên tôi không biết là việc công thức tính sai có phải hay không.

Nếu phải thì vấn đề tốc độ chỉ là phụ. Chuyện "kết quả sai mà không hay" mới là chuyện chính. Nếu code ban đầu chạy vèo vèo thì có lẽ chủ thớt không hề biết là mẫu số của mình bị hơi lệch một chút.
Chạy code chỉ trong vòng 1/10 giây nhưng khám phá chỗ sai mất vài ngày? Tôi thà chạy nửa ngày nhưng thấy chỗ sai trong vòng 15 phút.
Do em ko để ý, thấy code của anh quanghai1969 chạy cái vèo là xong, các kết quả đầu giống với kết quả em làm bằng tay, nên em ko kiểm tra lại, nhờ anh siwtom phát hiện em mới kiểm tra lại, đúng là code của anh quanghai1969 bị lệch 1 -2%. Sửa k+2 lại thành k trong công thức mới giống kết quả em làm bằng tay.

Code ở bài #5 của anh siwtom chạy đúng với yêu cầu của em và mất khoảng 75 giây.

Code của anh quanghai1969 ở bài #6 và anh huuthang_bd chạy cũng đúng nhưng nhanh hơn của anh siwtom (mất khoảng vài giây thôi).

Chân thành cảm ơn các anh (chị) đã nhiệt tình góp ý và giúp đỡ.
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom