说我有一个大小为500的ArrayList<String>
,然后我想用索引有效地连接字符串(从1开始):1-100,101-200,...,401-500字符串(所以我想得到5个字符串而不是500个字符串)。我以为我可以使用StringBuilder
然后使用.toString
但.toString()
StringBuilder
方法会创建一个新字符串,因此我会有效地创建5 * 2 = 10
个字符串这很糟糕(这些字符串真的很大,而我的空间不足)。什么是最好的记忆和时间有效的方法吗?
到目前为止我尝试了什么:
有一个错字:我的意思是StringBuilder
而不是StringBuffer
。我使用StringBuilder
在这个for
上使用简单的ArrayList<String>
循环。所以我使用3x空格(1x - 用于初始ArrayList
,2x - 用于StringBuilder
,3x - 当调用sb.toString()
时有效创建返回new String(value, 0, count);
)
答案 0 :(得分:5)
一种选择是使用List#subList
(因为它只是List
的视图,不应再使用更多内存)。然后,您可以在其上拨打String#join
:
String.join(" " /*Delimiter*/, list.subList(0, 100 /*Exclusive*/));
将其放入for循环中并将每个String
存储到String[]
的索引中,你就可以了!
根据大众需求,这里有一个替代解决方案可能效率更高,但必须用JMH正确标记:
String[] strings = new String[5];
for (int i = 0; i < 5; i++) {
List<String> subList = list.subList(100 * i, 100 * (i + 1));
StringBuilder sb = new StringBuilder(subList.stream().mapToInt(String::length).sum());
for (int j = 0; j < 100; j++) {
sb.append(subList.get(i));
}
strings[i] = sb.toString();
}
如果您提前了解每个子列表的长度总和,或者将List#stream
的调用替换为自己的for循环,则可以进行改进。
答案 1 :(得分:0)
由于您将问题标记为Java 8,这是一个功能更强大的解决方案(不一定更有效):
Map<Integer, String> result = IntStream.range(0, 500).boxed()
.collect(Collectors.groupingBy(
i -> i / 100,
Collectors.mapping(strings::get, Collectors.joining())));
除了创建流的开销之外,由于Collectors.joining()
在内部使用StringBuilder
,因此在内存使用方面应与@ Jacob的解决方案类似。