### Question:
FunctionalUtils { public static <K,V> Map<K,Pair<List<V>,List<V>>> cogroup(List<Pair<K,V>> left,List<Pair<K,V>> right) { Map<K,Pair<List<V>,List<V>>> ret = new HashMap<>(); Map<K,List<V>> leftMap = groupByKey(left); Map<K,List<V>> rightMap = groupByKey(right); for(Map.Entry<K,List<V>> entry : leftMap.entrySet()) { K key = entry.getKey(); if(!ret.containsKey(key)) { List<V> leftListPair = new ArrayList<>(); List<V> rightListPair = new ArrayList<>(); Pair<List<V>,List<V>> p = Pair.of(leftListPair,rightListPair); ret.put(key,p); } Pair<List<V>,List<V>> p = ret.get(key); p.getFirst().addAll(entry.getValue()); } for(Map.Entry<K,List<V>> entry : rightMap.entrySet()) { K key = entry.getKey(); if(!ret.containsKey(key)) { List<V> leftListPair = new ArrayList<>(); List<V> rightListPair = new ArrayList<>(); Pair<List<V>,List<V>> p = Pair.of(leftListPair,rightListPair); ret.put(key,p); } Pair<List<V>,List<V>> p = ret.get(key); p.getSecond().addAll(entry.getValue()); } return ret; }  static Map<K,Pair<List<V>,List<V>>> cogroup(List<Pair<K,V>> left,List<Pair<K,V>> right); static Map<K,List<V>> groupByKey(List<Pair<K,V>> listInput); static List<Pair<K,V>> mapToPair(Map<K,V> map);  }### Answer:
@Test public void testCoGroup() { List<Pair<String,String>> leftMap = new ArrayList<>(); List<Pair<String,String>> rightMap = new ArrayList<>(); leftMap.add(Pair.of("cat","adam")); leftMap.add(Pair.of("dog","adam")); rightMap.add(Pair.of("fish","alex")); rightMap.add(Pair.of("cat","alice")); rightMap.add(Pair.of("dog","steve")); Map<String,Pair<List<String>,List<String>>> assertion = new HashMap<>(); assertion.put("cat",Pair.of(Arrays.asList("adam"),Arrays.asList("alice"))); assertion.put("dog",Pair.of(Arrays.asList("adam"),Arrays.asList("steve"))); assertion.put("fish",Pair.of(Collections.<String>emptyList(),Arrays.asList("alex"))); Map<String, Pair<List<String>, List<String>>> cogroup = FunctionalUtils.cogroup(leftMap, rightMap); assertEquals(assertion,cogroup); }