Apex String Exercises

My previous post, Use Apex To Get First Letters In Each Word, was fun. Instead of implementing something specific, I tinkered around with basic String manipulation in Apex which isn’t something I’ve done much of.

I wanted to see how easy it is to do a few more String manipulations so I performed the following String exercises. Try implementing this functionality too and compare it with my solutions below.

  • Reverse String Without Loops
  • Create String Iterable
  • Get Words
  • Word Count
  • Get Longest Word
  • Index Words By Length
  • Get Longest Words

Reverse String Without Loops Exercise

Create a function that takes in a String “input” and returns the input in reverse order BUT implement the function without using any loops and without any built-in reverse functions. If the input is ‘abc’, the function returns ‘cba’.

At one of my previous employers, this was one of the interview questions used and it filtered out a decent number of candidates.

Create String Iterable Exercise

The Use Apex To Get First Letters In Each Word post uses a traditional for loop to iterate over the characters in the second solution but it felt “klunky”. I was curious if one could create a custom iterator to encapsulate iterating the characters in the string. One can but it can only be used in a while loop. I wanted to use this in a for-each loop but that’s not possible.

The exercise is to create a custom IterableString class that lets one use it to iterate over the characters in the String. Implement it so it can be used like this:

String input = 'Some Words Here';

IterableString is = new IterableString(input);

while(is.hasNext()) {
    String currentCharacter = is.next();
}

Get Words Exercise

Create a function that takes in a String “input” and returns a List<String> where each element is a word in the given string containing only alphanumeric characters. For example, if the function is given the input ‘The dog likes to bark.’, then [‘The’, ‘dog’, ‘likes’, ‘to’, ‘bark’] is returned.

Word Count Exercise

Create a function that takes in a String “input” and returns the count of the number of words in the input. If there are no words, 0 is returned. For example, if the function is given the input “The dog likes to bark.”, then 5 is returned.

Get First Longest Word Exercise

Create a function that takes in a String “input” and return the first longest word in the “input”. If there are no words, return an empty string. For example, if the function is given the input ‘The dog likes to bark.’, then ‘likes’ is returned.

Get Longest Words Exercise

Create a function that takes in a String “input” and return the longest words in the “input” in a List<String>. If there are no words, return an empty List<String>. For example, if the function is given the input ‘The dogs like to bark.’, then [‘dogs’, ‘like’, ‘bark’] is returned.

Index Words By Length Exercise

Create a function that takes in a String “input” and returns a map<Integer, List<String>> whose keys are the length of each word in the sentence and whose value are all the words of that length. If there are no words, an empty map is returned. For example, if the function is given the input ‘The dogs like to bark.’, then the map contains:

3 => [‘The’],

4 => [‘dogs’, ‘like’, ‘bark],

2 => [‘to’]

Reverse String Exercise Solution

public static String reverseString(String stringToReverse) {
    if (String.isBlank(stringToReverse)) {
        return '';
    }

    if (stringToReverse.length() == 1) {
        return stringToReverse;
    }

    return stringToReverse.right(1) + 
           reverseString(stringToReverse.left(stringToReverse.length() - 1));
}

Create String Iterable Solution

public class IterableString implements Iterator<String> {
    private Integer length = 0;
    private String inputToIterate = null;
    private Integer currentIndex = -1;

    public IterableString(String input) {
        this.inputToIterate = input;

        if (String.isNotEmpty(inputToIterate)) {
            length = inputToIterate.length();
        }
    }

    public Boolean hasNext() {
        return currentIndex < length - 1;
    }

    public String next() {
        if (hasNext()) {
            ++currentIndex;

            Integer characterCode = inputToIterate.charAt(currentIndex);
            String currentCharacter = String.fromCharArray(new Integer[]{ characterCode });

            return currentCharacter;
        }
        else {
            throw new NoSuchElementException();
        }
    }
}

Get Words Solution

public static List<String> getWords(String input) {

    List<String> words = new List<String>();

    // If no string, return empty string.
    if (String.isBlank(input)) {
        return words;
    }

    String currentWord = '';
    IterableString is = new IterableString(input);

    while(is.hasNext()) {
        String currentCharacter = is.next();

        if (currentCharacter.isWhitespace() == false) {
            if (currentCharacter.isAlphanumeric()) {
                currentWord += currentCharacter;
            }
        }
        // current character is whitespace which separates words so current word is over.
        else {
            if (String.isNotBlank(currentWord)) {
                words.add(currentWord);
            }

            currentWord = '';
        }
    }

    // The last word typically doesn't have whitespace at the end so if there's a word, add it.
    if (String.isNotBlank(currentWord)) {
        words.add(currentWord);
    }

    return words;
}

Word Count Solution

public static Integer getWordCount(String input) {
    List<String> words = getWords(input);

    return words.size();
}

One downside of this solution is that it uses a lot of memory since it passes the parsed list of words back and then use the list size.

Get First Longest Word Solution #1

public static String getFirstLongestWord(String input) {
    List<String> words = getWords(input);
    Integer wordCount = words.size();

    if (wordCount == 0) {
        return '';
    }

    String longestWord = words[0];

    // Starts at second word.
    for (Integer wordIndex = 1; wordIndex < wordCount; ++wordIndex) {
        String currentWord = words[wordIndex];

        if (currentWord.length() > longestWord.length()) {
            longestWord = currentWord;
        }
    }

    return longestWord;
}

Get First Longest Word Solution #2

public static String getLongestWord2(String input) {
    List<String> longestWords = getLongestWords(input);

    if (longestWords.isEmpty()) {
        return '';
    }

    return longestWords[0];
}

Index Words By Length Solution

public static Map<Integer, List<String>> indexWordsByLength(String input) {
    List<String> words = getWords(input);

    Map<Integer, List<String>> wordsIndexedByLength = new Map<Integer, List<String>>();

    for (String word : words) {
        Integer wordLength = word.length();

        List<String> wordsOfThisLength = wordsIndexedByLength.get(wordLength);

        if (wordsOfThisLength == null) {
            wordsOfThisLength = new List<String>();
                 
            wordsIndexedByLength.put(wordLength, wordsOfThisLength);
        }

        wordsOfThisLength.add(word);
    }

    return wordsIndexedByLength;
}

Get Longest Words Solution

public static List<String> getLongestWords(String input) {
    Map<Integer, List<String>> wordsIndexedByLength = indexWordsByLength(input);

    if (wordsIndexedByLength.isEmpty()) {
        return new List<String>();
    }

    List<Integer> wordLengths = new List<Integer>(wordsIndexedByLength.keySet());
    wordLengths.sort();
        
    return wordsIndexedByLength.get( wordLengths[wordLengths.size() - 1] );
}