2014-07-21 15 views
6

Có phương pháp API thư viện Scala (và nếu không, một cách thành ngữ) để lấy danh sách tất cả các chỉ mục cho chuỗi con (đích) trong chuỗi lớn hơn (nguồn)? Tôi đã cố gắng xem qua ScalaDoc, nhưng không thể tìm thấy bất cứ điều gì rõ ràng. Có rất nhiều phương pháp làm rất nhiều điều hữu ích, tôi đoán tôi chỉ không gửi các cụm từ tìm kiếm phù hợp. Ví dụ: nếu tôi có một chuỗi nguồn "tên: Yo, tên: Jim, tên: tên, tên: bozo" và tôi sử dụng chuỗi đích của "name:", tôi muốn quay lại Liệt kê [Int] của Danh sách (0, 8, 17, 27).Trả về tất cả các chỉ mục của một chuỗi con cụ thể

Dưới đây là hack nhanh chóng của tôi để giải quyết vấn đề:

def indexesOf(source: String, target: String, index: Int = 0, withinOverlaps: Boolean = false): List[Int] = { 
    def recursive(index: Int, accumulator: List[Int]): List[Int] = { 
     if (!(index < source.size)) accumulator 
     else { 
     val position = source.indexOf(target, index) 
     if (position == -1) accumulator 
     else { 
      recursive(position + (if (withinOverlaps) 1 else target.size), position :: accumulator) 
     } 
     } 
    } 

    if (target.size <= source.size) { 
     if (!source.equals(target)) { 
     recursive(0, Nil).reverse 
     } 
     else List(0) 
    } 
    else Nil 
    } 

Bất kỳ hướng dẫn bạn có thể cho tôi thay thế này với một điểm vào thư viện tiêu chuẩn thích hợp sẽ được đánh giá rất nhiều.

CẬP NHẬT 2014/Jul/22:

Lấy cảm hứng từ câu trả lời Siddhartha Dutta, tôi tighted lên mã của tôi. Nó bây giờ trông như thế này:

def indexesOf(source: String, target: String, index: Int = 0, withinOverlaps: Boolean = false): List[Int] = { 
    @tailrec def recursive(indexTarget: Int, accumulator: List[Int]): List[Int] = { 
     val position = source.indexOf(target, indexTarget) 
     if (position == -1) accumulator 
     else 
     recursive(position + (if (withinOverlaps) 1 else target.size), position :: accumulator) 
    } 
    recursive(index, Nil).reverse 
    } 

Thêm vào đó, nếu tôi có một chuỗi nguồn "aaaaaaaa" và tôi sử dụng một chuỗi mục tiêu của "aa", tôi muốn theo mặc định để lấy lại một danh sách [Int] của Danh sách (0, 2, 4, 6) bỏ qua tìm kiếm bắt đầu bên trong chuỗi con tìm thấy. Mặc định có thể được ghi đè bằng cách chuyển "true" cho tham số withinOverlaps trong trường hợp "aaaaaaaa"/"aa" sẽ trả về Danh sách (0, 1, 2, 3, 4, 5, 6).

+1

Không, đó không phải là "một [chuẩn] phương pháp". Ngoài ra, vì đây là mã hoạt động, nó * có thể * phù hợp hơn để xem xét mã. – user2864740

+0

@ chaotic3quilibrium Bất kỳ cách nào bạn có thể BSD cấp phép phương pháp đó để ông chủ không giận tôi nếu tôi sao chép/điều chỉnh nó? :) – ericpeters

+0

@ericpeters Đó là sự hiểu biết của tôi rằng bất kỳ đoạn mã được đăng ở đây trên StackOverflow có thể được giả định về cơ bản là miền công cộng; tức là không bị cản trở bởi bất kỳ ràng buộc giấy phép nào hạn chế khả năng cắt/dán/sửa đổi/tùy chỉnh đoạn mã của bạn thành bất kỳ ngữ cảnh nào bạn cần. – chaotic3quilibrium

Trả lời

6

Tôi luôn có xu hướng tiếp cận với túi thủ thuật regex với các vấn đề như thế này. Tôi sẽ không nói nó là thích hợp, nhưng đó là một địa ngục ít hơn rất nhiều mã. :)

val r = "\\Qname\\E".r 
val ex = "name:Yo,name:Jim,name:name,name:bozo" 

val is = r.findAllMatchIn(ex).map(_.start).toList 

Các dấu ngoặc kép \\Q\\E là không cần thiết đối với trường hợp này, nhưng nếu chuỗi bạn đang tìm kiếm có bất kỳ ký tự đặc biệt, sau đó nó sẽ được.

+0

Rất đẹp. Tôi đã dành ít hơn hai phút để đánh giá cách tiếp cận regex trước khi bật mã Scala của tôi. Thật tuyệt khi có nhiều cách để tìm kiếm con mèo tìm kiếm chuỗi. – chaotic3quilibrium

+0

BTW, bạn cũng có thể thay đổi dòng đầu tiên thành "" "\ Qname \ E" "". R nếu bạn muốn sử dụng regex thuần túy (dưới dạng sao chép/dán không bị loại bỏ khỏi một số nguồn khác). Các tùy chọn báo giá ba trong Scala là tuyệt vời! – chaotic3quilibrium

1

Một mã nhỏ để có được tất cả các chỉ số
gọi phương pháp dưới đây như getAllIndexes (nguồn, mục tiêu)

def getAllIndexes(source: String, target: String, index: Int = 0): List[Int] = { 
     val targetIndex = source.indexOf(target, index) 
     if(targetIndex != -1) 
      List(targetIndex) ++ getAllIndexes(source, target, targetIndex+1) 
     else 
      List() 
     } 
+0

Điều này dường như trả lại danh sách theo thứ tự ngược lại, tức là Danh sách (27, 17, 8, 0), phải không? Ngoài ra, bạn có thể tối ưu hóa hai nếu đường dẫn. Thay thế đầu tiên "List (targetIndex) ++ get ..." với "targetIndex :: get ...". Và thứ hai thay thế "List()" bằng "Nil". – chaotic3quilibrium

+1

Không phương thức nào trả về danh sách theo thứ tự tăng dần theo các chỉ mục tức là Danh sách (0,8,17,27). Tối ưu hóa là chính xác. –

+0

Tôi vừa thử cuộc gọi của bạn và sau khi thêm chú thích @tailrec, tôi nhận được một lỗi trình biên dịch nói rằng nó không phải là đệ quy đuôi (với cả hai ++ hoặc: :). Tuy nhiên, mã nhỏ hơn của bạn đã truyền cảm hứng cho tôi, vì vậy tôi đã cung cấp bản cập nhật để hiển thị mã của tôi được thắt chặt. Tôi cũng đã thêm một trường hợp thử nghiệm khác (ví dụ "aaaaaaaa", "aa") để hiển thị lợi ích của tham số withinOverlaps tùy chọn. – chaotic3quilibrium

Các vấn đề liên quan