How to Map Over a List of Lists in Java

The challenge

Write a function which maps a function over the lists in a list:

public static <T,R> R[][] gridMap(Function<T,R> fn, T[][] list)

Example 1:

int[][] x = {{1,2,3},
             {4,5,6}};

gridMap(e -> e + 1, x); // {{2,3,4},{5,6,7}}
gridMap(e -> e * e, x); // {{1,4,9},{16,25,36}}

Example 2:

char[][] x = {{'h','E','l','l','O'},{'w','O','r','L','d'}};

gridMap(e -> Character.toUpperCase(e), x); // {{'H','E','L','L','O'},{'W','O','R','L','D'}}

The solution in Java code

Option 1:

import java.util.function.Function;
import java.util.Arrays;

public class Solution {
  public static <T, R> Object[][] gridMap(Function<T, R> fn, T[][] list) {
    return Arrays.stream(list).map(xs -> Arrays.stream(xs).map(fn).toArray()).toArray(Object[][]::new);
  }
}

Option 2:

import java.util.function.Function;

public class Solution {
    public static <T,R> R[][] gridMap(Function<T,R> fn, T[][] list) {
        R[][] result = (R[][]) new Object[list.length][];
        for (int i = 0; i < list.length; i++) {
            result[i] = (R[]) new Object[list[i].length];
            for (int j = 0; j < list[i].length; j++) {
                result[i][j] = fn.apply(list[i][j]);
            }
        }
        return result;
    }
}

Option 3:

import java.util.function.Function;
import java.util.Arrays;

public class Solution{
    public static <T,R> R[][] gridMap(Function<T,R> fn, T[][] list){
      return (R[][]) Arrays.stream(list)
                .map(e -> Arrays.stream(e).map(fn).toArray(Object[]::new))
                .toArray(Object[][]::new);
    }
}

Test cases to validate our solution

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;

public class SolutionTest{
    private static final Integer[][] num = {{1,2,3,4},{5,6,7,8,9},{0,2,4}};
    private static final Character[][] chr = {{'h','E','l','l','O'},{'w','O','r','L','d'}};
    
    @Test
    public void addition(){
        assertEquals(new Integer[][]{{2,3,4,5},{6,7,8,9,10},{1,3,5}}, Solution.gridMap(e -> e + 1,num));
    }
    
    @Test
    public void multiplication(){
        assertEquals(new Integer[][]{{2,4,6,8},{10,12,14,16,18},{0,4,8}}, Solution.gridMap(e -> e * 2,num));
    }
    
    @Test
    public void power(){
        assertEquals(new Integer[][]{{1,4,9,16},{25,36,49,64,81},{0,4,16}}, Solution.gridMap(e -> (int)Math.pow(e, 2),num));
    }
    
    @Test
    public void upper(){
        assertEquals(new Character[][]{{'H','E','L','L','O'},{'W','O','R','L','D'}}, Solution.gridMap(e -> Character.toUpperCase(e),chr));
    }
    
    @Test
    public void lower(){
        assertEquals(new Character[][]{{'h','e','l','l','o'},{'w','o','r','l','d'}}, Solution.gridMap(e -> Character.toLowerCase(e),chr));
    }
}