2014-07-21 26 views
6

Czy istnieje metoda API biblioteki Scala (a jeśli nie, metoda idiomatyczna), aby uzyskać listę wszystkich indeksów dla podłańcucha (celu) w większym ciągu (źródle)? Próbowałem przeglądać ScalaDoc, ale nie byłem w stanie znaleźć niczego oczywistego. Jest tak wiele metod robiących tak wiele użytecznych rzeczy, domyślam się, że po prostu nie przesyłam odpowiednich wyszukiwanych słów.Zwróć wszystkie indeksy określonego podłańcucha.

Na przykład, jeśli mam ciąg źródłowy "name: Yo, name: Jim, name: name, name: bozo" i używam docelowego ciągu znaków "name:", chciałbym otrzymać Lista [Int] listy (0, 8, 17, 27).

Oto mój szybki hack, aby rozwiązać ten problem:

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 
    } 

Wszelkie wskazówki może dać mi zastępując to z odpowiednim standardzie punktu wejścia biblioteki byłoby bardzo mile widziane.

UPDATE 2014/lipiec/22:

Zainspirowany odpowiedź Siddhartha Dutta, w I tighted mój kod. Teraz wygląda to tak:

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 
    } 

Dodatkowo, jeśli mam ciąg źródłowy „AAAAAAAA” i używam ciąg docelowy „aa”, chciałbym domyślnie wrócić listy [Int] z Lista (0, 2, 4, 6), która pomija wyszukiwanie rozpoczynające się od znalezionego podciągu. Wartość domyślna może być nadpisana przez podanie "true" dla parametru withinOverlaps, który w przypadku "aaaaaaa"/"aa" zwróciłby listę (0, 1, 2, 3, 4, 5, 6).

+1

nie, to nie jest „[średnia] Metoda”. Ponieważ jest to działający kod, * może * być bardziej odpowiedni do przeglądania kodu. – user2864740

+0

@ chaotic3quilibrium Jakikolwiek sposób BSD Licencjonowałbyś tę metodę, aby szef nie wpadł w szał na mnie, gdybym ją skopiował/zaadaptował? :) – ericpeters

+0

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@icicpeters tj. nieobciążone żadnymi ograniczeniami licencyjnymi ograniczającymi Twoją zdolność do wycinania/wklejania/modyfikowania/dostosowywania fragmentu do dowolnego kontekstu, którego potrzebujesz. – chaotic3quilibrium

Odpowiedz

6

Zawsze jestem skłonny sięgać do torby z sztuczkami regex z takimi problemami jak ten. Nie powiedziałbym, że to jest właściwe, ale jest to o wiele mniej kodu. :)

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

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

Cytaty \\Q i \\E nie są konieczne w tym przypadku, ale jeśli ciąg szukasz ma żadnych znaków specjalnych, to będzie.

+0

Very nice. Spędziłem mniej niż dwie minuty, oceniając podejście do wyrażenia regularnego przed pobieraniem kodu Scala. Fajnie jest mieć więcej niż jeden sposób na skracanie kota wyszukiwania ciągów. – chaotic3quilibrium

+0

BTW, możesz także zmienić pierwszy wiersz na "" "\ Qname \ E" "" r, jeśli chcesz użyć czystego wyrażenia regularnego (jako kopii/wklejenia bez znaku z innego źródła). Opcja potrójnych cudzysłowów w Scali jest niesamowita! – chaotic3quilibrium

1

małym kod aby wszystkie wskaźniki
połączeń poniżej Sposób getAllIndexes (źródła docelowy)

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

Ta opcja powoduje wyświetlenie listy w odwrotnej kolejności, tj. Listy (27, 17, 8, 0), prawda? Dodatkowo można zoptymalizować obie ścieżki. Pierwsze zastąpienie "List (targetIndex) ++ get ..." z "targetIndex :: get ...". A drugi zastępuje "List()" przez "Nil". – chaotic3quilibrium

+1

Nie metoda zwraca listę w porządku rosnącym, jak w przypadku indeksów, np. Lista (0,8,17,27). Optymalizacje są poprawne. –

+0

Właśnie próbowałem twojego połączenia i po dodaniu adnotacji @tailrec, dostaję błąd kompilatora stwierdzający, że to nie jest rekursywny ogon (z + ++ lub: :). Jednak twój mniejszy kod zainspirował mnie, więc podałem aktualizację, aby pokazać, że mój kod jest zaostrzony. Dodałem także inny przypadek testowy (przykład "aaaaaaa", "aa"), aby pokazać korzyści opcjonalnego parametru intraOverlaps. – chaotic3quilibrium