20

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?

4

3 回答 3

24

您可以简单地删除您的构建器并将其内联以获得(更长的)单线

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

这是一种最优的结果,因为它Iterables.transform是惰性的,因此没有分配临时列表。AFAIK 有一些小的低效率:

  • 分配一个FluentIterable
  • 调整用于结果的数组的大小

如果您真的很在意速度,可以对其进行基准测试并与类似的东西进行比较

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

和一个手卷循环。

更新

虽然第一种方法肯定是最易读的方法,但它会导致数组调整大小以及最终缩小到所需大小的一些分配。对于长度为 1234567 的列表,有以下调整大小的步骤:

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

和最后的收缩

1574801 -> 1234567

更新 2

正如路易斯和克里斯所说,最佳解决方案是

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

因为它不包括数组复制。这Lists.transform是一个惰性集合并ImmutableList.copyOf查询其大小以分配适当大小的数组的结果。请注意,既不是Iterables.transform也不FluentIterable是那么有效。

于 2013-10-15T14:24:19.253 回答
1

我认为你已经写了几个这样的单行代码的例子。转换是通过最少的新对象创建完成的。事实上,Guava 以懒惰的方式工作:它不会遍历您的列表,创建其他元素并将其放入另一个列表。它创建惰性列表,根据需要填充其元素,例如,当您迭代新列表时。我认为对于这个用例,带有闭包的 java 8 不会快太多,因为它会执行类似的字节码,但语法会更短。

于 2013-10-15T14:16:21.897 回答
1

我想input.stream().collect(toImmutableList())这是你需要的。见文档

于 2018-07-21T18:39:24.693 回答