Start learning free

LESSON 197 OF 414 · STRINGS

Strings in Scala: Indexing, Slicing and Immutability

Lesson Read the full explanation

The Scala String is an object that represents a sequence of characters, each identified by one index.

Creation:

To create strings in Scala, you use double quotes like this:

var greeting = "Hello"

Accessing characters:

To access the characters in a string, you can use the index in parentheses.

The following example returns the first character of a string with the index zero:

val str = "Hello"
val ch = str(0) 
// ch is 'H'

Getting the length:

We can get the length of a string using length.

For example, to access the last character of the string, you use the length - 1 index:

val str = "Hello"
val ch = str(str.length - 1) 
// ch is 'o'

Concatenating strings via + operator:

To concatenate two or more strings, you use the + operator:

var name = "John"
var str = "Hello " + name

println(str) // prints "Hello John"

If you want to assemble a string piece by piece, you can use the += operator:

var greet = "Welcome"
var name = "John"
greet += " to AlgoCademy, "
greet += name

println(greet) // "Welcome to AlgoCademy, John"

When concatenating many strings, it is recommended to use StringBuilder for performance

String slicing

We often want to get a substring of a string. For this, we use the substring() method.

substring(startIndex, endIndex) returns the substring from startIndex to endIndex:

var str = "JavaScript"
var substr = str.substring(2, 6)

println(substr) // prints "vaSc"

The startIndex is a zero-based index at which the substring() start extraction.

The endIndex is also zero-based index before which the substring() ends the extraction. The substr will not include the character at the endIndex index.

If you omit the endIndex, the substring() extracts to the end of the string:

var str = "JavaScript"
var substr = str.substring(4)

println(substr) // "Script"

String Immutability:

In Scala, String values are immutable, which means that they cannot be altered once created.

For example, the following code:

var myStr = "Bob"
myStr(0) = 'J' // compile error: value update is not a member of String

cannot change the value of myStr to "Job", because the contents of myStr cannot be altered.

Note that this does not mean that myStr cannot be changed, just that the individual characters of a string literal cannot be changed. The only way to change myStr would be to assign it with a new string, like this:

var myStr = "Bob"
myStr = "Job"
//or
myStr = "J" + myStr.substring(1, 3)

Immutability affects performance when concatenating many strings, it is recommended to use StringBuilder for performance


Convert a string to an array of characters:

When we have to change characters often in a string, we want a way of doing this quickly. Because strings are immutable, we change a character by creating a whole new string, which is O(n).

But arrays are mutable and changing an element in an array is O(1). So what we can do is first convert our string to an array of characters, operate on that array and then convert the array back to a string.

We can convert a string to an array using the toCharArray() method like this:

var str = "Andy"
val myArr = str.toCharArray()

// myArr is ['A', 'n', 'd', 'y']
myArr(0) = 'a'
myArr(2) = 'D'

// We convert an array of chars back to a string using the constructor:
str = String(myArr)

println(str) // "anDy"

Iterating through the characters:

We can iterate through the elements of a string using indices and a for loop like this:

val myStr = "Andy"
for (i <- myStr.indices) {
    println(myStr(i))
}

// This will print the characters 'A', 'n', 'd' and 'y' on different lines

This takes O(n) time, where n is the length of the string we iterate on.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 7
    Ctrl + Enter to check

    SCALA · STRINGS

    Strings in Scala, explained

    What a Scala String is

    A Scala String is a sequence of characters, each with a zero-based index. Under the hood it is Java's String, so it brings Java's methods with it, and Scala adds collection-style helpers on top. Strings are written in double quotes:

    var greeting = "Hello"
    

    A single character is a Char and is written in single quotes, like 'H'. The two types are different: "H" is a string of length 1, 'H' is a character.

    Accessing characters and getting the length

    Scala reads a character with parentheses around the index, not square brackets. The property length gives the number of characters, so the last character is at length - 1:

    val str = "Hello"
    println(str(0))              // H
    println(str(str.length - 1)) // o
    println(str.length)          // 5
    

    Both results are Char values. Reading an index that doesn't exist, such as str(10), throws a StringIndexOutOfBoundsException when the code runs.

    Concatenation

    The + operator joins strings and produces a new one. For a var, += joins and stores the result back in the same variable:

    var greet = "Welcome"
    val name = "John"
    greet += " back, "
    greet += name
    println(greet) // Welcome back, John
    

    Every join builds a new string, so a loop that adds one piece at a time copies the growing text on each pass. For many pieces, use a StringBuilder:

    val sb = new StringBuilder
    sb.append("ab")
    sb.append('c')
    println(sb.toString) // abc
    

    Slicing with substring

    substring(startIndex, endIndex) returns the characters from startIndex up to but not including endIndex. With a single argument it goes to the end of the string:

    val s = "Scala"
    println(s.substring(1, 3)) // ca
    println(s.substring(2))    // ala
    println(s.substring(2, 4)) // al
    

    The length of the result is endIndex - startIndex. An end index larger than the length, as in "Scala".substring(2, 6), throws a StringIndexOutOfBoundsException.

    Immutability

    A string can't be changed once it exists. Trying to assign to one of its positions doesn't compile:

    var myStr = "Bob"
    myStr(0) = 'J'
    

    The compiler reports value update is not a member of String. What you can do is point the variable at a new string:

    var myStr = "Bob"
    myStr = "Job"
    // or, building the new string from parts of the old one
    myStr = "J" + myStr.substring(1, 3)
    

    Notice the difference: the first string is never altered; myStr simply refers to a different one afterwards. This only works because myStr is a var. With a val, reassignment is a compile error.

    Changing characters through an array

    Creating a new string costs O(n), because every character is copied. If you need to change many characters, convert the string to an array, change the array, and convert back. An Array[Char] is mutable, and changing one element is O(1):

    var str = "Andy"
    val myArr = str.toCharArray()
    myArr(0) = 'a'
    myArr(2) = 'D'
    str = String(myArr)
    println(str) // anDy
    

    Here String(myArr) calls the Java String constructor, and it works without new in Scala 3. The array can be a val: the variable always refers to the same array, and the elements inside it are still free to change. Another way to turn the array back into a string is myArr.mkString.

    Looping over a string

    The property indices is the range 0 to length - 1, so a loop can visit every position:

    val myStr = "Andy"
    for (i <- myStr.indices) {
        println(myStr(i))
    }
    

    It prints A, n, d and y on separate lines. The loop takes O(n) time for a string of length n.

    The lesson's exercise

    The exercise turns "Java" into "TypeScript", using the operations above in order.

    1. Create a var named lang holding "Java". It must be a var, because the next step changes it.
    2. Append "script" with +=. A new string is built and stored back, so lang is "Javascript".
    3. Create a val named substr with lang.substring(4), the part from index 4 to the end: "script".
    4. Create a var named newLang from "Type" + substr, which is "Typescript".
    5. Copy it into a mutable array: val charArray = newLang.toCharArray().
    6. Set charArray(4) to 'S'. Index 4 is the fifth character, the lowercase s of script.
    7. Build a string from the array with String(charArray) and assign it to newLang, which now holds "TypeScript".

    The full solution:

    var lang = "Java"
    lang += "script"
    val substr = lang.substring(4)
    var newLang = "Type" + substr
    val charArray = newLang.toCharArray()
    charArray(4) = 'S'
    newLang = String(charArray)
    

    Common mistakes

    • Using square brackets. str[0] is not Scala; write str(0).
    • Mixing up Char and String. charArray(4) = "S" doesn't compile, because the array holds Char values and "S" is a String.
    • Forgetting that the end index is excluded. "Scala".substring(1, 3) is "ca", two characters, not three.
    • Expecting a method to change the string. lang.substring(4) leaves lang as it was; only the returned value is new.
    • Declaring with val and then reassigning. Use var for a variable that gets a new string later.

    Key takeaways

    • Characters are read with s(i); the last index is s.length - 1.
    • + and += build new strings; a StringBuilder suits many pieces.
    • substring excludes the end index.
    • Strings are immutable. To change characters, go through an array and convert back.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free