FunctionalFunctions { @SuppressWarnings("unchecked") private static List<List<Object>> zip(List<Object> args, boolean jagged) { List<List<Object>> lists = new ArrayList<>(); Integer resultSize = null; for (Object o : args) { if (o instanceof List) { List<Object> l = (List<Object>)o; if (resultSize == null) { resultSize = l.size(); } else if (jagged) { resultSize = Math.max(l.size(), resultSize); } else { resultSize = Math.min(l.size(), resultSize); } lists.add(l); } } if (resultSize == null) { return new ArrayList<>(); } return IntStream.range(0, resultSize) .mapToObj(i -> { List<Object> o = new ArrayList<>(); for (List<Object> list : lists) { o.add(i < list.size() ? list.get(i) : null); } return o; }) .collect(Collectors.toList()); }    }
@Test @SuppressWarnings("unchecked") public void testZip() { Map<String, Object> variables = ImmutableMap.of( "list1" , ImmutableList.of(1, 2, 3) ,"list2", ImmutableList.of(4, 5, 6) ); for (String expr : ImmutableList.of( "ZIP(list1)" , "ZIP( [1, 2, 3])" ) ) { List<List<Object>> o = (List<List<Object>>) run(expr, variables); assertEquals(3, o.size()); for (int i = 0; i < 3; ++i) { List l = o.get(i); assertEquals(1, l.size()); assertEquals(i+1, l.get(0)); } } for (String expr : ImmutableList.of( "ZIP(list1, list2)" , "ZIP( [1, 2, 3], [4, 5, 6] )" , "ZIP( [1, 2, 3], [4, 5, 6, 7] )" ) ) { List<List<Object>> o = (List<List<Object>>) run(expr, variables); assertEquals(3, o.size()); for (int i = 0; i < 3; ++i) { List l = o.get(i); assertEquals(2, l.size()); assertEquals(i+1, l.get(0)); assertEquals(i+4, l.get(1)); } } for (String expr : ImmutableList.of( "REDUCE(ZIP(list1, list2), (s, x) -> s + GET_FIRST(x) * GET_LAST(x), 0)" , "REDUCE(ZIP( [1, 2, 3], [4, 5, 6] ), (s, x) -> s + GET_FIRST(x) * GET_LAST(x), 0)" , "REDUCE(ZIP( [1, 2, 3], [4, 5, 6, 7] ), (s, x) -> s + GET_FIRST(x) * GET_LAST(x), 0)" ) ) { int o = (int) run(expr, variables); assertEquals(1*4 + 2*5 + 3*6, o, 1e-7); } }