How to Perform Alphabetical Addition in Java


The challenge

Your task is to add up letters to one letter.

The function will be given an array of single-character Strings, each one being a letter to add.

Notes:

  • Letters will always be lowercase.
  • Letters can overflow (see second to last example of the description)
  • If no letters are given, the function should return 'z'

Examples:

addLetters("a", "b", "c") = "f"
addLetters("a", "b") = "c"
addLetters("z") = "z"
addLetters("z", "a") = "a"
addLetters("y", "c", "b") = "d" // notice the letters overflowing
addLetters() = "z"

The solution in Java code

Option 1:

public class Solution {

    public static String addLetters(String... letters) {
        String abc = "zabcdefghijklmnopqrstuvwxyz";
        int sum = 0;
        for (int i = 0; i < letters.length; i++) {
            sum += abc.indexOf(letters[i]);
        }
        return String.valueOf(abc.charAt(sum % 26));
    }
}

Option 2:

import static java.util.stream.Stream.of;

class Solution {
  static String addLetters(String... letters) {
    int sum = of(letters).mapToInt(l -> l.charAt(0) - 96).sum() % 26 + 96;
    return "" + (char) (sum != 96 ? sum : 122);
  }
}

Option 3:

import java.util.Arrays;

public class Solution {
  public static String addLetters(String... letters) {
    int sum = Arrays.stream(letters)
                    .flatMapToInt(String::chars)
                    .map(letter -> letter == 'z' ? 0 : letter - 'a' + 1)
                    .sum();
    int overflow = sum % 26;
    return overflow == 0 ? "z" : Character.valueOf((char)(overflow + 'a' - 1)).toString();
  }
}

Test cases to validate our solution

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
import java.util.Arrays;
import java.util.Random;

public class SolutionTest {
    @Test
    public void fixedTests() {
        assertEquals("f", Solution.addLetters("a", "b", "c"));
        assertEquals("z", Solution.addLetters("z"));
        assertEquals("c", Solution.addLetters("a", "b"));
        assertEquals("c", Solution.addLetters("c"));
        assertEquals("a", Solution.addLetters("z", "a"));
        assertEquals("d", Solution.addLetters("y", "c", "b"));
        assertEquals("z", Solution.addLetters());
    }
    
    private String solution(String... letters) {
        int sum = Arrays.stream(letters).mapToInt(s->s.charAt(0)-96).sum() % 26;
        return sum == 0 ? "z" : String.valueOf((char)(sum+96));
    }
    
    @Test
    public void randomTests() {
        Random rnd = new Random();
        for (int i = 0; i < 100; ++i) {
            String[] letters = rnd.ints(97, 123)
                                  .limit(rnd.nextInt(10) + 1)
                                  .mapToObj(c -> String.valueOf((char) c))
                                  .toArray(String[]::new);
            assertEquals(solution(letters), Solution.addLetters(letters));
        }
    }
}