@Test
  public void groupBy() {
    ImmutableMap<String, Integer> map = this.newMapWithKeysValues("1", 1, "2", 2, "3", 3, "4", 4);

    Function<Integer, Boolean> isOddFunction = object -> IntegerPredicates.isOdd().accept(object);

    Multimap<Boolean, Integer> expected;

    switch (map.size()) {
      case 1:
        expected = FastListMultimap.newMultimap(Tuples.pair(Boolean.TRUE, 1));
        break;
      case 2:
        expected =
            FastListMultimap.newMultimap(
                Tuples.pair(Boolean.TRUE, 1), Tuples.pair(Boolean.FALSE, 2));
        break;
      case 3:
        expected =
            FastListMultimap.newMultimap(
                Tuples.pair(Boolean.TRUE, 1),
                Tuples.pair(Boolean.TRUE, 3),
                Tuples.pair(Boolean.FALSE, 2));
        break;
      case 4:
        expected =
            FastListMultimap.newMultimap(
                Tuples.pair(Boolean.TRUE, 1),
                Tuples.pair(Boolean.TRUE, 3),
                Tuples.pair(Boolean.FALSE, 2),
                Tuples.pair(Boolean.FALSE, 4));
        break;
      default:
        expected = FastListMultimap.newMultimap();
        break;
    }

    Multimap<Boolean, Integer> actual = map.groupBy(isOddFunction);
    Assert.assertEquals(HashBagMultimap.newMultimap(expected), HashBagMultimap.newMultimap(actual));

    Multimap<Boolean, Integer> actualFromTarget =
        map.groupBy(isOddFunction, FastListMultimap.<Boolean, Integer>newMultimap());
    Assert.assertEquals(
        HashBagMultimap.newMultimap(expected), HashBagMultimap.newMultimap(actualFromTarget));
  }
  @Test
  public void groupByEach() {
    ImmutableBag<Integer> immutableBag = this.newBag().collect(Integer::valueOf);

    MutableMultimap<Integer, Integer> expected = HashBagMultimap.newMultimap();
    int keys = this.numKeys();
    immutableBag.forEachWithOccurrences(
        (each, parameter) -> {
          HashBag<Integer> bag = HashBag.newBag();
          Interval.fromTo(each, keys)
              .forEach((int eachInt) -> bag.addOccurrences(eachInt, eachInt));
          expected.putAll(-each, bag);
        });
    Multimap<Integer, Integer> actual = immutableBag.groupByEach(new NegativeIntervalFunction());
    Assert.assertEquals(expected, actual);

    Multimap<Integer, Integer> actualWithTarget =
        immutableBag.groupByEach(
            new NegativeIntervalFunction(), HashBagMultimap.<Integer, Integer>newMultimap());
    Assert.assertEquals(expected, actualWithTarget);
  }
  @Test
  public void groupBy() {
    FastList<Integer> iterable =
        FastList.newWithNValues(
            10000000,
            new Function0<Integer>() {
              private int current;

              public Integer value() {
                if (this.current < 4) {
                  return Integer.valueOf(this.current++);
                }
                this.current = 0;
                return Integer.valueOf(4);
              }
            });
    iterable.shuffleThis();
    Multimap<String, Integer> expected = iterable.toBag().groupBy(String::valueOf);
    Multimap<String, Integer> expectedAsSet = iterable.toSet().groupBy(String::valueOf);
    Multimap<String, Integer> result1 =
        ParallelIterate.groupBy(iterable.toList(), String::valueOf, 100);
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result1));
    Multimap<String, Integer> result2 = ParallelIterate.groupBy(iterable.toList(), String::valueOf);
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result2));
    Multimap<String, Integer> result3 =
        ParallelIterate.groupBy(
            iterable.toSet(),
            String::valueOf,
            SynchronizedPutUnifiedSetMultimap.<String, Integer>newMultimap(),
            100);
    Assert.assertEquals(expectedAsSet, result3);
    Multimap<String, Integer> result4 =
        ParallelIterate.groupBy(
            iterable.toSet(),
            String::valueOf,
            SynchronizedPutUnifiedSetMultimap.<String, Integer>newMultimap());
    Assert.assertEquals(expectedAsSet, result4);
    Multimap<String, Integer> result5 =
        ParallelIterate.groupBy(
            iterable.toSortedSet(),
            String::valueOf,
            SynchronizedPutUnifiedSetMultimap.<String, Integer>newMultimap(),
            100);
    Assert.assertEquals(expectedAsSet, result5);
    Multimap<String, Integer> result6 =
        ParallelIterate.groupBy(
            iterable.toSortedSet(),
            String::valueOf,
            SynchronizedPutUnifiedSetMultimap.<String, Integer>newMultimap());
    Assert.assertEquals(expectedAsSet, result6);
    Multimap<String, Integer> result7 =
        ParallelIterate.groupBy(
            iterable.toBag(),
            String::valueOf,
            SynchronizedPutHashBagMultimap.<String, Integer>newMultimap(),
            100);
    Assert.assertEquals(expected, result7);
    Multimap<String, Integer> result8 =
        ParallelIterate.groupBy(
            iterable.toBag(),
            String::valueOf,
            SynchronizedPutHashBagMultimap.<String, Integer>newMultimap());
    Assert.assertEquals(expected, result8);
    Multimap<String, Integer> result9 =
        ParallelIterate.groupBy(iterable.toList().toImmutable(), String::valueOf);
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result9));
    Multimap<String, Integer> result10 =
        ParallelIterate.groupBy(iterable.toSortedList(), String::valueOf, 100);
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result10));
    Multimap<String, Integer> result11 =
        ParallelIterate.groupBy(iterable.toSortedList(), String::valueOf);
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result11));

    Multimap<String, Integer> result12 =
        ParallelIterate.groupBy(
            iterable,
            String::valueOf,
            MultiReaderFastListMultimap.<String, Integer>newMultimap(),
            100);
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result12));
    Multimap<String, Integer> result13 =
        ParallelIterate.groupBy(
            iterable, String::valueOf, MultiReaderFastListMultimap.<String, Integer>newMultimap());
    Assert.assertEquals(expected, HashBagMultimap.newMultimap(result13));

    Multimap<String, Integer> result14 =
        ParallelIterate.groupBy(
            iterable,
            String::valueOf,
            MultiReaderHashBagMultimap.<String, Integer>newMultimap(),
            100);
    Assert.assertEquals(expected, result14);
    Multimap<String, Integer> result15 =
        ParallelIterate.groupBy(
            iterable, String::valueOf, MultiReaderHashBagMultimap.<String, Integer>newMultimap());
    Assert.assertEquals(expected, result15);

    Multimap<String, Integer> result16 =
        ParallelIterate.groupBy(
            iterable,
            String::valueOf,
            MultiReaderUnifiedSetMultimap.<String, Integer>newMultimap(),
            100);
    Assert.assertEquals(expectedAsSet, result16);
    Multimap<String, Integer> result17 =
        ParallelIterate.groupBy(
            iterable,
            String::valueOf,
            MultiReaderUnifiedSetMultimap.<String, Integer>newMultimap());
    Assert.assertEquals(expectedAsSet, result17);
  }
 public <V> HashBagMultimap<V, T> groupByEach(
     Function<? super T, ? extends Iterable<V>> function) {
   return this.groupByEach(function, HashBagMultimap.<V, T>newMultimap());
 }
 public <V> HashBagMultimap<V, T> groupBy(Function<? super T, ? extends V> function) {
   return this.groupBy(function, HashBagMultimap.<V, T>newMultimap());
 }