Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guava one-liner for transforming immutable lists

Tags:

java

guava

I think there must be a one-liner Guava solution for transforming an immutable list into another immutable list, but I can't find it. Suppose we have the following objects:

ImmutableList<String> input = ImmutableList.of("a", "b", "c");
Function<String, String> function = new Function<String, String>() {
    @Override
    public String apply(String input) {
        return input + input;
    }
};

The transformation can be achieved like this:

Iterable<String> transformedIt = Iterables.transform(input, function);
ImmutableList<String> output = ImmutableList.<String>builder().addAll(transformedIt).build();

or like this:

List<String> transformedList = Lists.transform(input, function);
ImmutableList<String> output2 = ImmutableList.copyOf(transformedList);

but I think that there must be somewhere a performance-optimized one-liner for this kind of transformation, without intermediate objects, I just can't find it. Where is it?

like image 516
WannaKnow Avatar asked Oct 15 '13 14:10

WannaKnow


People also ask

How do you make an array list immutable?

No, you cannot make the elements of an array immutable. But the unmodifiableList() method of the java. util. Collections class accepts an object of the List interface (object of implementing its class) and returns an unmodifiable form of the given object.

Is immutable list ordered?

Immutable List Static Factory Methods. The List. of static factory methods provide a convenient way to create immutable lists. A list is an ordered collection, where duplicate elements are typically allowed.

Which of the following is not an immutable collection in Java 8?

A mutable collection is not a subtype of an immutable collection.


2 Answers

You can simply remove your builder and inline it to get a (bit longer) one-liner

ImmutableList<String> output =
    ImmutableList.copyOf(Iterables.transform(input, function));

This is sort of optimal as the result of Iterables.transform is lazy, so no temporary list gets allocated. There are AFAIK some minor inefficiencies:

  • Allocation of a FluentIterable
  • Resizing of the array used for the result

If you really care a lot about the speed, you could benchmark it and compare to something like

ArrayList<String> tmp = Lists.newArrayListWithCapacity(input.size());
Iterables.addAll(tmp, Iterables.transform(input, function));
ImmutableList<String> output = ImmutableList.copyOf(tmp);

and to a handrolled loop.

UPDATE

While the first approach is surely the most readable one, it incurs some allocations for array resizing and also the final shrinking to desired size. With a list of length 1234567, there are the following resizing steps:

4 -> 7 -> 11 -> 17 -> 26 -> 40 -> 61 -> 92 -> 139 -> 209 -> 314 -> 472 -> 709 -> 1064 -> 1597 -> 2396 -> 3595 -> 5393 -> 8090 -> 12136 -> 18205 -> 27308 -> 40963 -> 61445 -> 92168 -> 138253 -> 207380 -> 311071 -> 466607 -> 699911 -> 1049867 -> 1574801

and the final shrinking

1574801 -> 1234567

UPDATE 2

As Louis and Chris said, the optimal solution is

ImmutableList<String> output =
    ImmutableList.copyOf(Lists.transform(input, function));

as it includes no array copying. This works as the result of Lists.transform is a lazy collection and ImmutableList.copyOf queries its size in order to allocate a properly sized array. Note that neither Iterables.transform nor FluentIterable are that efficient.

like image 194
maaartinus Avatar answered Nov 02 '22 06:11

maaartinus


I think that you have already written several examples of such one-liners. The transformation is done with minimal creation of new objects. Indeed Guava works in lazy manner: it does not iterate over your list, creates other elements and put it to another list. It creates lazy list that is filled as far as its elements are needed, e.g. while you are iterating over the new list. I think that java 8 with closures will not be too much faster for this use case because it will execute similar byte code but the syntax will be shorter.

like image 1
AlexR Avatar answered Nov 02 '22 05:11

AlexR