2014-07-21 31 views
6

Daha büyük bir dize (kaynak) içindeki bir alt dizenin (hedef) tüm dizinlerinin bir listesini almak için bir Scala kitaplığı API yöntemi var mı (yoksa, bir deyimsel yol) var mı? ScalaDoc'a bakmaya çalıştım ama belli bir şey bulamadı. Pek çok yararlı şey yapan birçok yöntem var, sanırım doğru arama terimlerini sunmuyordum.Belirli bir alt dizenin tüm indekslerini döndürme

Örneğin, "name: Yo, name: Jim, name: name, name: bozo" adlı bir kaynak dizilim varsa ve "name:" hedef dizgisini kullanırsam, geri dönmek istiyorum. Listenin [Int] listesini (0, 8, 17, 27).

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 
    } 

Herhangi bir rehberlik beni büyük takdir uygun bir standart kütüphane giriş noktası ile bu değiştirerek verebilir:

İşte bu sorunu çözmek için benim hızlı beygir.

GÜNCELLEME 2014/Temmuz/22: Siddhartha Dutta cevabı esinlenerek

, benim kodu tighted. Şimdi şuna benzer:

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 
    } 

Ayrıca, ben "aaaaaaaa" kaynağı dizesi var ve "aa" hedef dize kullanırsanız, geri bir List [Uluslararası] önüne geçmeye varsayılan olarak istiyorum Bulunan bir alt dizenin içinden başlayan bir aramayı atlayan Liste (0, 2, 4, 6). Varsayılan, "aaaaaaaa"/"aa" durumunda List (0, 1, 2, 3, 4, 5, 6) döndüren withinOverlaps parametresi için "true" iletilerek geçersiz kılınabilir.

+1

Hayır "a [Standart] yöntemi" yok alır. Ayrıca, bu çalışma kodu olduğundan, kod incelemesi için * daha uygun olabilir. – user2864740

+0

@ chaotic3quilibrium BSD Lisansı herhangi bir şekilde bu şekilde patron adam ben kopyalamazsa/uyarlarsam bana kızmaz mı? :) – ericpeters

+0

@ericpeters StackOverflow üzerinde buraya gönderilen herhangi bir kod parçacığının aslında kamuya açık bir alan olduğu varsayılabilir. snippet'i ihtiyaç duyduğunuz herhangi bir içeriğe göre kesme/yapıştırma/değiştirme/özelleştirme yeteneğinizi sınırlayan herhangi bir lisans kısıtlaması tarafından engellenmez. – chaotic3quilibrium

cevap

6

Her zaman böyle bir sorunla uğraşırken, normal ifadelere sahip çantalara ulaşmaya yatkınım. Ben uygun olduğunu söyleyemem, ama çok daha az kod cehennem. :)

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

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

tırnak \\Q ve \\E bu durum için gerekli değildir, ancak aradığınız dize herhangi bir özel karakterler varsa, o zaman olacak.

+0

Çok güzel. Scala kodumu kırmadan önce regex yaklaşımını değerlendiren iki dakikadan az harcadım. Dize arama kedisini derlemek için birden fazla yol var. – chaotic3quilibrium

+0

BTW, ayrıca saf regex'i kullanmak istiyorsanız ilk satırı "" "\ Qname \ E" "". R (başka bir kaynaktan çıkarılamayan bir kopya/yapıştır) olarak da değiştirebilirsiniz. Scala'da üçlü teklif seçeneği harika! – chaotic3quilibrium

1

küçük bir kodu tüm dizinler
arama getAllIndexes aşağıdaki yöntem (kaynak, hedef)

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

Bu, listeyi ters sırada, yani Liste (27, 17, 8, 0), sağa döndürüyor gibi görünüyor. Ek olarak, iki yolu en iyi duruma getirebilirsiniz. İlk değiştiren "Liste (targetIndex) ++" ... "ile" targetIndex :: olsun ... ". Ve ikinci "Nil" ile "List()" yerine. – chaotic3quilibrium

+1

Yöntem, listeyi indeksler, yani Liste (0,8,17,27) 'ye göre artan sırada döndürür. Optimizasyonlar doğru. –

+0

Sadece aramayı denedim ve @tailrec ek açıklama ekledikten sonra, (+ veya + ile birlikte) kuyruk özyinelemesini belirten bir derleyici hatası alıyorum. Ancak, daha küçük kodunuz bana ilham verdi, bu yüzden kodumun sıkıldığını göstermek için bir güncelleme yaptım. Ayrıca, isteğe bağlı withinOverlaps parametresinin faydasını göstermek için başka bir test durumu ("aaaaaaaa", "aa" örneği) ekledim. – chaotic3quilibrium

İlgili konular