Bế tắc thuật toán

Liên hệ QC

khongtu19bk

Thành viên hoạt động
Tham gia
5/12/09
Bài viết
147
Được thích
69
File excel thứ 1(sheet1) chứa data cần lọc, như là trang ghi văn bản một cách thông thường

File excel thứ 2(sheet1) ở cột A chứa data điều kiện lọc.

Ví dụ ở file excel thứ 2, tại cột A ghi như sau:

ABC
BC
DE
DEFMN


Như vậy, nhiệm vụ của chương trình là phải tìm trên file excel 1(sheet1) chỗ nào có ABC hoặc BC hoặc DE hoặc DEFMN thì thay bằng ""

Ví dụ làm bằng tay thì sẽ phải làm như sau:

ở file excel 1, ấn ctr+H và nhập ABC -> thay bằng ""
tương tự
Nhập DEFMN -> thay bằng ""
Nhập DE -> thay bằng ""

Chú ý:
Ở ví dụ trên, tại sao không nhập DE -> thay bằng "" trước. Vì nếu làm như vậy ta sẽ không xóa đi được chuỗi kí tự "DEFMN" (nếu có)

Chú ý 2: trường hợp nhập ABC -> thay bằng "" mà máy hiện thông báo không tìm thấy "ABC" trên file excel 1 thì ở trên file excel 2, cell chứa kí tự ABC sẽ bị tô đỏ, nhằm mục đích thông báo rằng, điều kiện này không cần thiết.

Quả thực đây là một bài toán hóc búa về mặt giải thuật, hơn nữa trong trường hợp file excel điều kiện, chứa nhiều điều kiện, thì việc ấn ctr+H thay thế chúng bằng chuỗi rỗng "" là rất khó khăn.

Mong được mọi người chỉ giáo.
 
Lần chỉnh sửa cuối:
Thực ra chính bạn cũng đã đưa ra cách tiếp cận về thuật toán rồi còn gì. Nhé.
1. Duyệt qua danh mục các điều kiện tại Sheet 2
2. Lần lượt thay thế tại sheet1, nếu không có phép thay thế nào được thực hiện thì bôi đỏ điều kiện.
Để tránh các tình huống thay thế chuỗi trong chuỗi điều kiện thì thêm vào thuật toán xử lý trước đối với các chuỗi có số ký tự là dài nhất trước (như vậy bạn cần phải quản lý danh sách cần tìm để thay thế trước khi tiến hành thay thế tuần tự)
Vậy chèn thêm 1 thuật toán con trước bước 1 là được.
Đây là một cách tư duy thuật toán đơn giản chúng ta có thể bắt đầu thực hiện đấy.
Về sử dụng Code thì bạn hãy tìm xem cần phải thực hiện bao nhiêu nghiệp vụ: ví dụ
1. Tìm chuỗi dài nhất làm trước - do đó cần có một đoạn thủ tục con thực hiện việc sắp xếp chuỗi trước (có thể dùng mảng, sắp xếp theo độ dài ký tự hoặc dùng tính năng Sort của Excel đối với điều kiện Sort là độ dài).
2. Thực hiện thay thế, kiểm tra, bôi đỏ.
Xin phép được ví dụ như vậy.
 
Upvote 0
Bạn đã hiểu được ý tưởng của mình. chính mình cũng đang lăn tăn trong việc sẽ phải chỉnh lại data điều kiện. Tức là ở cột A của data điều kiện. Cần có một thuật toán sắp xếp, chuỗi nào dài thì cho lên trên, chuỗi nào ngắn thì xếp xuống dưới. Đây cũng chính là vấn đề bế tắc của mình.
Ai có thể giúp mình code sắp xếp các chuỗi kí tự theo độ dài chuỗi giảm dần được không? :(

ABCDEF
XYZMNP
MNP
XYZ
MN
XY
M
X
 
Lần chỉnh sửa cuối:
Upvote 0
Hic!
Bạn đã ra được đến vấn đề này rồi còn gì mà phải hỏi ai có thể giúp được nữa?
Cách 1: Hãy sử dụng tính năng Sắp xếp của Excel và dùng tính năng ghi Macro để hình thành mã.
Tất nhiên bạn cần thêm cột phụ B (theo khả năng hạn chế của tôi) với công thức =Len(A1). Sau đó sắp xếp theo cột B.
Cách này có thể làm thay đổi thứ tự các ô điều kiện

Cách 2: Sử dụng thuật toán sắp xếp
Có nhiều cách khác nhau, một trong những cách đơn giản nhất là sử dụng thuật toán sắp xếp nổi bọt. Bạn có thể sử dụng Google để thực hiện.
Thứ tự các bước làm là:
1. Đọc lần lượt từng ô thuộc vùng điều kiện và đồng thời tổ chức sắp xếp ngay.
2. Tiếp tục các bước tôi đã nói trong bài trước.

Bạn xem đoạn code ví dụ nhé
PHP:
Sub TheSort()
    ' Buoc 1: Sap xep thanh mang tuan tu tu be den lon
    Dim SortRange As Range, thecell As Range
    Dim i As Long
    Dim tmpArr() As String, tmpString As String
    SortRange = Range("SortRange")
     
    ReDim tmpArr(SortRange.Cells.Count - 1)
    
    thecell = SortRange.Cells(1)
    While thecell <> ""
        'Ghi gia tri cung do dai vao, gan them gia tri neu da co du lieu
        'neu chua co thi co dau ","
        tmpArr(Len(thecell) - 1) = tmpArr(Len(thecell) - 1) & "," & thecell
        thecell = thecell.Offset(1)
    Wend
    ' bay gio duyet qua mang cho den het va dua vao mot bien ky tu tmpString
    For i = 0 To UBound(tmpArr)
        If tmpArr(i) <> "" Then tmpString = tmpString & "," & tmpArr(i)
    Next
    ' thay the chuoi co 2 ky tu ",," lien nhau (viec nay chi xay ra 1 lan)
    ' cung cha can phai lam viec thay the nay, chi can khi duyet tuan tu thi bo qua cac
    ' phan tu mang co gia tri rong ""
    tmpString = Replace(tmpString, ",,", ",")
    ' chuyen chuoi da xu ly thanh mang de tien hanh sap xep
    Dim SortedArr As Variant
    SortedArr = Split(tmpString, ",")
    
    'Buoc 2: thay the
    ' duyet tu cuoi mang ve dau bang vong lap
    For i = UBound(SortedArr) To LBound(SortedArr) Step -1
    ' code thay the day
    Next
End Sub
Thuật toán sắp xếp mình sử dụng đây mang tính chất lai ghép giữa QuickSort và Library Sort kết hợp với tính năng đặc trưng của sử dụng mảng và quản lý chuỗi của VB (hàm Split) và đoạn thủ thuật ghép các ký tự cùng độ dài vào một phần tử mảng.
Cách này không có giá trị áp dụng phổ dụng mà chỉ tùy thuộc từng bài toán thôi.
(Giải thích một chút như sau)
1. Định nghĩa 1 mảng bằng số phần tử điều kiện (bất kể nó có các phần tử có cùng độ dài, chỉ cần biết số ô cần xét).
2. Khi độ dài ký tự của 1 ô bằng 2 thì gán với phần tử 2 của mảng, nếu phần tử này đã được gán thì cũng vẫn gán thêm và có thêm dấu phẩy phân cách, điều này dẫn đến bất kỳ phần tử mảng nào được gán cũng sẽ có dấu phẩy đằng trước.
3. Duyệt lại mảng, sẽ có chỗ có dữ liệu chỗ không và đưa vào chuỗi tạm, phần tử nào không có số liệu thì bỏ qua, vậy sẽ xảy ra tình huống có chỗ sẽ có 2 dấu phẩy liền nhau. Vì thế tôi dùng phép thay thế.
Bạn có thể cải thiện bằng cách dùng lệnh iif() để kiểm soát xem phần tử đã được gán giá trị hay chưa trước khi gán thêm.
...
Sau đó dùng hàm split để đưa đoạn chuỗi vừa xử lý thành mảng để dùng mảng và xử lý tuần tự từ cao xuống thấp.
Cách làm là thế đấy
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn bạn, về cách 2, mình có nghĩ tới nhưng nếu làm như vậy e rằng sẽ rất chậm nếu số ô là vô cùng lớn(thuật toán nổi bọt quá tự nhiên, và chắc nếu ai một khi động não một tẹo cũng có thể tự hình dung ra được kiểu suy nghĩ như thế). Mình tính dùng Quicksort vì có thể sẽ tăng tốc độ hơn thông qua việc chia làm đôi để so sánh. Nhưng ngay một lúc đọc thì chưa hiểu được (trừu tượng quá, khi có thời gian mình sẽ đọc thêm, cảm thụ cái hay của tinh hoa nhân loại).
Tạm thời mình dùng cách 1, chính là cách mà bạn nói.
Cảm ơn bạn rất nhiều :)
<Cách 1 giúp chúng ta giải quyết đc vấn đề, nhưng chính việc dùng lệnh sắp xếp có sẵn trong excel đã là một cách bóp chết sự sáng tạo trong ta nếu ta bằng lòng với nó, vì ta không hiểu tại sao nó lại sắp xếp đc như thế>
 
Lần chỉnh sửa cuối:
Upvote 0
Thêm một điều nữa, không có gì gọi là bóp chết sáng tạo cả! Việc sử dụng macro để thay thế các việc nhàm chán đã là sáng tạo rồi và bạn sẽ có hàng tỷ cách để biến hóa macro để nó làm những việc bạn cần. Không nên cho rằng cứ nghĩ cái khác mới là sáng tạo. Hãy dùng tốt cái ta có đã để làm nền cho các sáng tạo đột phá khác!
Về điểm này, tôi không đồng ý với bạn. Bản thân tôi cũng học từ những điều tưởng như chả sáng tạo tí nào như vậy đấy! Sáng tạo là kết quả của quá trình tích lũy!
 
Upvote 0
Cảm ơn bạn, về cách 2, mình có nghĩ tới nhưng nếu làm như vậy e rằng sẽ rất chậm nếu số ô là vô cùng lớn(thuật toán nổi bọt quá tự nhiên, và chắc nếu ai một khi động não một tẹo cũng có thể tự hình dung ra được kiểu suy nghĩ như thế). Mình tính dùng Quicksort vì có thể sẽ tăng tốc độ hơn thông qua việc chia làm đôi để so sánh. Nhưng ngay một lúc đọc thì chưa hiểu được (trừu tượng quá, khi có thời gian mình sẽ đọc thêm, cảm thụ cái hay của tinh hoa nhân loại).
Tạm thời mình dùng cách 1, chính là cách mà bạn nói.
Cảm ơn bạn rất nhiều :)
<Cách 1 giúp chúng ta giải quyết đc vấn đề, nhưng chính việc dùng lệnh sắp xếp có sẵn trong excel đã là một cách bóp chết sự sáng tạo trong ta nếu ta bằng lòng với nó, vì ta không hiểu tại sao nó lại sắp xếp đc như thế>
Thế thì xem bài này: Sort mảng 2 chiều
Tôi nghĩ chỉ cần chế biến lại tí xíu (phối hợp với Dictionary Object) thì bài toán Sort theo LEN của bạn chỉ là chuyện nhỏ
Về tốc độ thì... KHỎI BÀN. Dám cam đoan với bạn rằng nó nhanh hơn cả chức năng sort của Excel
 
Upvote 0
Web KT

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

Back
Top Bottom