ACollectionHelper { public static <T, X, E extends Throwable> Map<X, Collection<T>> groupBy (Iterable<T> coll, AFunction1<? super T, ? extends X, E> f) throws E { final Map<X, Collection<T>> result = new HashMap<>(); for(T o: coll) { final X key = f.apply(o); Collection<T> perKey = result.get(key); if(perKey == null) { perKey = new ArrayList<>(); result.put(key, perKey); } perKey.add(o); } return result; }  static Set<T> createSet(Iterator<T> elements); static Set<T> createSet(Iterable<T> elements); static Set<U> createSet(Iterator<T> elements, AFunction1<T,U,E> f); static Set<U> createSet(Iterable<T> elements, AFunction1<T,U,E> f); static String mkString(Iterable<?> iterable); static String mkString(Iterable<?> iterable, String separator); static String mkString(Iterable<?> iterable, String prefix, String separator, String suffix); static AOption<T> find(Iterable<T> coll, APredicate<? super T, E> pred); static boolean forAll(Iterable<T> coll, APredicate<? super T, E> pred); static boolean exists(Iterable<T> coll, APredicate<? super T, E> pred); static Collection<X> map(Iterable<T> coll, AFunction1<? super T, ? extends X, E> f); static List<X> map(List<T> coll, AFunction1<? super T, ? extends X, E> f); static Set<X> map(Set<T> coll, AFunction1<? super T, ? extends X, E> f); static Collection<X> flatMap(Iterable<T> coll, AFunction1<? super T, ? extends Iterable<X>, E> f); static List<X> flatMapList(Iterable<T> coll, AFunction1<? super T, ? extends Iterable<X>, E> f); static Set<X> flatMapSet(Iterable<T> coll, AFunction1<? super T, ? extends Iterable<X>, E> f); static Collection<T> flatten(Iterable<? extends Iterable<T>> coll); static List<T> flattenList(Iterable<? extends Iterable<T>> coll); static Set<T> flattenSet(Iterable<? extends Iterable<T>> coll); static Collection<X> collect(Iterable<T> coll, APartialFunction<? super T, ? extends X, E> pf); static List<X> collect(List<T> coll, APartialFunction<? super T, ? extends X, E> pf); static Set<X> collect(Set<T> coll, APartialFunction<? super T, ? extends X, E> pf); static Collection<T> filter(Iterable<T> coll, APredicate<? super T, E> pred); static List<T> filter(List<T> coll, APredicate<? super T, E> pred); static Set<T> filter(Set<T> coll, APredicate<? super T, E> pred); static Collection<T> filterNot(Iterable<T> coll, APredicate<? super T, E> pred); static List<T> filterNot(List<T> coll, APredicate<? super T, E> pred); static Set<T> filterNot(Set<T> coll, APredicate<? super T, E> pred); static Map<X, Collection<T>> groupBy(Iterable<T> coll, AFunction1<? super T, ? extends X, E> f); static Map<X, List<T>> groupBy(List<T> coll, AFunction1<? super T, ? extends X, E> f); static Map<X, Set<T>> groupBy(Set<T> coll, AFunction1<? super T, ? extends X, E> f); static Map<AEqualsWrapper<X>, Collection<T>> groupBy(Iterable<T> coll, AFunction1<? super T, ? extends X, E> f, AEquality keyEquality); static Map<AEqualsWrapper<X>, List<T>> groupBy(List<T> coll, AFunction1<? super T, ? extends X, E> f, AEquality keyEquality); static Map<AEqualsWrapper<X>, Set<T>> groupBy(Set<T> coll, AFunction1<? super T, ? extends X, E> f, AEquality keyEquality); static R foldLeft(Iterable<T> coll, R startValue, AFunction2<R, ? super T, R, E> f); static R foldRight(List<T> coll, R startValue, AFunction2<R, ? super T, R, E> f); static ACollectionWrapper<T> asACollectionCopy(Collection<T> c); @SuppressWarnings("unchecked") static ACollectionWrapper<T> asACollectionView(Collection<T> c); static ASetWrapper<T> asASetView(Collection<T> c); @SuppressWarnings("unchecked") static AArrayWrapper<T> asArrayCopy(T[] c); static AArrayWrapper<T> asArrayView(T[] c); static List<T> asJavaUtilList(Iterable<T> c); static Collection<T> asJavaUtilCollection(Iterable<T> c); static List<T> asJavaUtilCollection(Iterator<T> c);  }
@Test public void testGroupByEquals() { final AFunction1NoThrow<String, Integer> len = new AFunction1NoThrow<String, Integer>() { @Override public Integer apply(String param) { return param.length(); } }; final Map<Integer, List<String>> grouped = ACollectionHelper.groupBy(Arrays.asList("a", "bc", "d", "efg", "hi", "j"), len); assertEquals(3, grouped.size ()); assertEquals(Arrays.asList("a", "d", "j"), grouped.get (1)); assertEquals(Arrays.asList("bc", "hi"), grouped.get (2)); assertEquals(Arrays.asList("efg"), grouped.get (3)); }
@Test public void testGroupByCustomEquality() { final AEquality equality = new AEquality() { @Override public boolean equals(Object o1, Object o2) { return ((Integer)o1)%2 == ((Integer)o2)%2; } @Override public int hashCode(Object o) { return 0; } }; final AFunction1NoThrow<String, Integer> len = new AFunction1NoThrow<String, Integer>() { @Override public Integer apply(String param) { return param.length(); } }; final Map<AEqualsWrapper<Integer>, List<String>> grouped = ACollectionHelper.groupBy(Arrays.asList("a", "bc", "d", "efg", "hi", "j"), len, equality); assertEquals(2, grouped.size ()); assertEquals(Arrays.asList("a", "d", "efg", "j"), grouped.get(new AEqualsWrapper<>(equality, 1))); assertEquals(Arrays.asList("bc", "hi"), grouped.get(new AEqualsWrapper<>(equality, 2))); }