如何在 Java 中有效地连接来自 ArrayList 的连续字符串间隔?
How do I effectively concat consecutive interval of strings from ArrayList in Java?
假设我有一个大小为 500 的 ArrayList<String>
,然后我想有效地连接具有索引的字符串(从 1 开始):1-100、101-200、...、401-500字符串(所以我想得到 5 个字符串而不是 500 个)。我以为我可以使用 StringBuilder
然后使用 .toString
但是 StringBuilder
的 .toString()
方法创建了一个新字符串,所以我会有效地创建 5 * 2 = 10
字符串不好(这些字符串真的很大,我还缺space)。执行此操作的最佳内存和时间效率方法是什么?
到目前为止我尝试了什么:
有一个错字:我的意思是 StringBuilder
而不是 StringBuffer
。我在这个 ArrayList<String>
上使用了一个 StringBuilder
和一个简单的 for
循环。所以我使用了 3x space(1x - 对于初始 ArrayList
,2x - 对于 StringBuilder
,3x - 当调用 sb.toString()
时有效地创建了 returns new String(value, 0, count);
)
一个选项是使用 List#subList
(因为这只是 List
的一个视图,不应再使用任何内存)。然后你可以在上面调用 String#join
:
String.join(" " /*Delimiter*/, list.subList(0, 100 /*Exclusive*/));
只需将其放入 for-loop 并将每个 String
存储到 String[]
的索引中即可!
应大众需求,这里有一个替代解决方案 可能 更有效,但必须 bench-marked 与 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();
}
如果提前知道每个sub-list的长度之和可以改进,或者用自己的for-loop.[=18替换对List#stream
的调用=]
由于您将问题标记为 Java 8,一个更实用的解决方案(不一定更有效):
Map<Integer, String> result = IntStream.range(0, 500).boxed()
.collect(Collectors.groupingBy(
i -> i / 100,
Collectors.mapping(strings::get, Collectors.joining())));
除了创建流的开销之外,它在内存使用方面应该与@Jacob 的解决方案相似,因为 Collectors.joining()
在内部使用 StringBuilder
。
假设我有一个大小为 500 的 ArrayList<String>
,然后我想有效地连接具有索引的字符串(从 1 开始):1-100、101-200、...、401-500字符串(所以我想得到 5 个字符串而不是 500 个)。我以为我可以使用 StringBuilder
然后使用 .toString
但是 StringBuilder
的 .toString()
方法创建了一个新字符串,所以我会有效地创建 5 * 2 = 10
字符串不好(这些字符串真的很大,我还缺space)。执行此操作的最佳内存和时间效率方法是什么?
到目前为止我尝试了什么:
有一个错字:我的意思是 StringBuilder
而不是 StringBuffer
。我在这个 ArrayList<String>
上使用了一个 StringBuilder
和一个简单的 for
循环。所以我使用了 3x space(1x - 对于初始 ArrayList
,2x - 对于 StringBuilder
,3x - 当调用 sb.toString()
时有效地创建了 returns new String(value, 0, count);
)
一个选项是使用 List#subList
(因为这只是 List
的一个视图,不应再使用任何内存)。然后你可以在上面调用 String#join
:
String.join(" " /*Delimiter*/, list.subList(0, 100 /*Exclusive*/));
只需将其放入 for-loop 并将每个 String
存储到 String[]
的索引中即可!
应大众需求,这里有一个替代解决方案 可能 更有效,但必须 bench-marked 与 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();
}
如果提前知道每个sub-list的长度之和可以改进,或者用自己的for-loop.[=18替换对List#stream
的调用=]
由于您将问题标记为 Java 8,一个更实用的解决方案(不一定更有效):
Map<Integer, String> result = IntStream.range(0, 500).boxed()
.collect(Collectors.groupingBy(
i -> i / 100,
Collectors.mapping(strings::get, Collectors.joining())));
除了创建流的开销之外,它在内存使用方面应该与@Jacob 的解决方案相似,因为 Collectors.joining()
在内部使用 StringBuilder
。