EC by Example: InjectInto

Learn one of the most general, flexible, and least understood iteration patterns in Eclipse Collections.

Grounds for Sculpture, Hamilton N.J.

Continuum Transfunctioner

Like the Continuum Transfunctioner from “Dude, Where’s my car”, the method injectInto is a very mysterious and powerful method, and its mystery is only exceeded by its power.

So what does injectInto do?

The method injectInto can be used to do pretty much anything. The method injects an initial value into a two argument function along with the first element of the collection, and calculates some result. That result is then passed to the next invocation of the function as the initial value along with the next element of the collection. And so on and so forth until all elements of the collection have been visited and a final result is returned.

The name injectInto is based on the inject:into: selector from Smalltalk. InjectInto is an alternative name for foldLeft or reduce.

I will illustrate ways to implement various algorithms using injectInto to show how mysterious and powerful it is.

Example: Min and Max

@Test
public void injectIntoMinAndMax()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);

Integer maxInt = Integer.MAX_VALUE;
Integer minValue = list.injectInto(maxInt, Math::min);
Assert.assertEquals(list.min(), minValue);

Integer minInt = Integer.MIN_VALUE;
Integer maxValue = list.injectInto(minInt, Math::max);
Assert.assertEquals(list.max(), maxValue);
}

Example: Sum

@Test
public void injectIntoSum()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);

Integer sum = list.injectInto(Integer.valueOf(0), Integer::sum);
    Assert.assertEquals(Integer.valueOf(15), sum);
}

Example: Product

@Test
public void injectIntoProduct()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);

Integer product =
list.injectInto(
Integer.valueOf(1),
(result, each) -> result * each);
    Assert.assertEquals(Integer.valueOf(120), product);
}

Example: Collect

@Test
public void injectIntoCollect()
{
MutableList<String> lowerCase =
Lists.mutable.with("a", "b", "c", "d", "e");
    MutableList<Object> upperCase =
lowerCase.injectInto(
Lists.mutable.empty(),
(list, each) -> list.with(each.toUpperCase()));
    Assert.assertEquals(
lowerCase.collect(String::toUpperCase),
upperCase);
}

Example: GroupBy

@Test
public void injectIntoGroupBy()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);
    MutableListMultimap<Integer, Integer> grouped = 
Multimaps.mutable.list.empty();
    list.injectInto(grouped, (multimap, each) -> {
multimap.put(each % 2, each);
return multimap;
});
    Assert.assertEquals(list.groupBy(each -> each % 2), grouped);
}

Example: Collectors.groupingBy

@Test
public void injectIntoGroupingBy()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);
    MutableMap<Integer, List<Integer>> grouped =
Maps.mutable.empty();
    list.injectInto(grouped, (map, each) -> {
map.getIfAbsentPut(each % 2,Lists.mutable::empty)
.add(each);
return map;
});
    Assert.assertEquals(
list.stream().collect(
Collectors.groupingBy(each -> each % 2)),
grouped);
}

Example: Detect

@Test
public void injectIntoDetect()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);
    Integer value = list.injectInto(
null,
(result, each) ->
result == null && each > 2 ? each : result);
    Assert.assertEquals(list.detect(each -> each > 2), value);
}

Example: Select

@Test
public void injectIntoSelect()
{
MutableList<Integer> list = Lists.mutable.with(1, 2, 3, 4, 5);
    MutableList<Integer> value = list.injectInto(
Lists.mutable.empty(),
(result, each) ->
each % 2 == 0 ? result.with(each) : result);
    Assert.assertEquals(list.select(each -> each % 2 == 0), value);
}

APIs covered in the examples

  1. injectInto — applies a two argument function to each element of a collection using an initial value, and then injecting the result of each application of the function into the next iteration.

Check out this presentation to learn more about the origins, design and evolution of the Eclipse Collections API.

Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.