如何在Java中有效地连接ArrayList中的连续字符串间隔?

问题描述 投票:2回答:2

假设我有一个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);

java java-8 stringbuilder
2个回答
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();
}

如果您提前知道每个子列表的长度总和,或者用自己的for循环替换对List#stream的调用,则可以改进它。


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的解决方案类似。

© www.soinside.com 2019 - 2024. All rights reserved.