2016-03-28 8 views
6

Chciałbym zamienić ciąg od "abcde" do "bcdea". Więc napisałem swój kod jak poniżej w KotlinKotlin: jak zamienić znak w String

var prevResult = "abcde" 
var tmp = prevResult[0] 

for (i in 0..prevResult.length - 2) { 
    prevResult[i] = prevResult[i+1] // Error on preveResult[i] 
} 

prevResult[prevResult.length-1] = tmp // Error on preveResult[prevResult.lengt-1] 

Wystąpił błąd w powyższej linii komentarza. Co zrobiłem źle? Jak mogę to naprawić i uzyskać to, czego chcę?

Odpowiedz

6

Podobnie jak w Javie są niezmienne, więc nie ma string.set(index, value) (co jest równoznaczne z string[index] = value).

Aby zbudować ciąg z elementów można użyć StringBuilder, skonstruować CharSequence i używać joinToString, działają na prostym tablicy (char[]) czy result = result + nextCharacter (tworzy nowy ciąg każdym razem - jest to najbardziej kosztowny sposób) .

Oto jak można to zrobić z StringBuilder:

var prevResult = "abcde" 
var tmp = prevResult[0] 

var builder = StringBuilder() 

for (i in 0..prevResult.length - 2) { 
    builder.append(prevResult[i+1]) 
} 

builder.append(tmp) // Don't really need tmp, use prevResult[0] instead. 
var result = builder.toString() 

jednak znacznie prostszy sposób, aby osiągnąć swój cel ("bcdea" z "ABCDE") jest po prostu "przenieść" jedna postać:

var result = prevResult.substring(1) + prevResult[0] 

, albo stosując Sequence metody:

var result = prevResult.drop(1) + prevResult.take(1) 
+0

Dzięki za dobre wytłumaczenie! – Elye

+0

Rozważ użycie 'buildString' jako bardziej zwięzłego sposobu budowania' String': https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/build-string.html – hotkey

0

S Ciągi są niezmienne, musisz skopiować łańcuch źródłowy do tablicy, dokonać zmian w tablicy, a następnie utworzyć nowy ciąg z zmodyfikowanej tablicy. Sprawdź:

  • getChars(), aby skopiować ciąg znaków do tablicy.
  • Wykonaj swój algorytm na tej macierzy, wprowadzając w nim zmiany w razie potrzeby.
  • Przekształć zmodyfikowaną tablicę z powrotem na ciąg znaków za pomocą String(char[]).
4

Można użyć drop(1) i first() (lub take(1)), aby zrobić to w jednym wierszu:

val str = "abcde" 
val r1 = str.drop(1) + str.first() 
val r2 = str.drop(1) + str.take(1) 

Jak do kodu, Kotlin String jest niezmienna i nie można modyfikować jej znaków. Aby osiągnąć to, co chcesz, możesz konwertować String do CharArray, modyfikować go, a następnie utworzyć nowy String z nim:

val r1 = str.toCharArray().let { 
    for (i in 0..it.lastIndex - 1) 
     it[i] = it[i+1] 
    it[it.lastIndex] = str[0] // str is unchanged 
    String(it) 
} 

(let służy do zwięzłości, aby uniknąć tworzenia większej liczby zmiennych)


Ponadto, można napisać bardziej ogólną wersję tej operacji jako extension function dla String:

fun String.rotate(n: Int) = drop(n % length) + take(n % length) 

Zastosowanie:

val str = "abcde" 
val r1 = str.rotate(1) 
+0

Zastanawiam się, jaka jest wydajność dla tych. W wersji naiwnej wersja z 'CharArray' musi być najbardziej mem-wydajna i mem-lokalna. Z drugiej strony JIT może zoptymalizować pozostałe, więc zamiast jednego jest 3. 1 – voddan

+1

@voddan, oto test z wynikiem: https://gist.github.com/h0tk3y/bc508a573abfe8e8b3b3. Wydaje się dość dziwne, ale drop + take pokazuje się trochę lepiej. – hotkey

+0

hah, nikt nie spodziewał się, że 'StringBuilder' zabłyśnie tutaj :) Dzięki za testy! – voddan

0

prostsze rozwiązanie: Wystarczy użyć toMutableList(), aby utworzyć MutableList char, a następnie dołączyć je wszystkie razem z joinToString.

Przykład:

Biorąc pod uwagę wejście String, chcemy zamienić znaki w pozycjach POSA i posB:

val chars = input.toMutableList() 
val temp = chars[posA] 
chars[posA] = chars[posB] 
chars[posB] = temp 
return chars.joinToString(separator = "")