Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,如何有效地从ArrayList中提取连续的字符串间隔?_Java_Java 8_Stringbuilder - Fatal编程技术网

在Java中,如何有效地从ArrayList中提取连续的字符串间隔?

在Java中,如何有效地从ArrayList中提取连续的字符串间隔?,java,java-8,stringbuilder,Java,Java 8,Stringbuilder,假设我有一个大小为500的ArrayList,然后我想用索引有效地压缩字符串(从1开始):1-100101-200,…,401-500个字符串(所以我想得到5个而不是500个字符串)。我想我可以使用StringBuilder然后使用.toString但是.toString()的StringBuilder方法会创建一个新字符串,所以我会有效地创建5*2=10字符串,这是不好的(这些字符串非常大,我缺少空间)。做这件事最节省内存和时间的方法是什么 我到目前为止所做的尝试: 有一个输入错误:我的意思是

假设我有一个大小为500的
ArrayList
,然后我想用索引有效地压缩字符串(从1开始):1-100101-200,…,401-500个字符串(所以我想得到5个而不是500个字符串)。我想我可以使用
StringBuilder
然后使用
.toString
但是
.toString()
StringBuilder
方法会创建一个新字符串,所以我会有效地创建
5*2=10
字符串,这是不好的(这些字符串非常大,我缺少空间)。做这件事最节省内存和时间的方法是什么

我到目前为止所做的尝试


有一个输入错误:我的意思是
StringBuilder
,而不是
StringBuffer
。我使用了一个
StringBuilder
,在
ArrayList
上有一个简单的
循环。所以我使用了3倍的空间(1x-用于初始
ArrayList
,2x-用于
StringBuilder
,3x-当调用
sb.toString()
时,它有效地创建了一个返回
新字符串(值,0,计数);

一个选项是使用
列表#子列表
(因为这只是
列表的一个视图
,不应该使用更多的内存)。然后,您可以在其上调用
String#join

String.join(" " /*Delimiter*/, list.subList(0, 100 /*Exclusive*/));
只需将其放入for循环中,并将每个
字符串
存储到
字符串[]
的索引中,就可以开始了


根据大众的需求,这里有一个可能更有效的替代解决方案,但必须使用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();
}
String[]strings=新字符串[5];
对于(int i=0;i<5;i++){
List subList=List.subList(100*i,100*(i+1));
StringBuilder sb=新的StringBuilder(subList.stream().mapToInt(String::length.sum());
对于(int j=0;j<100;j++){
sb.append(subList.get(i));
}
strings[i]=sb.toString();
}

如果您提前知道每个子列表的长度之和,或者将对
list#stream
的调用替换为自己的for循环,则可以改进该问题。

因为您将该问题标记为Java 8,这是一个更实用的解决方案(不一定更高效):

Map result=IntStream.range(0500).boxed()
.collect(收集器.groupingBy(
i->i/100,
Collectors.mapping(strings::get,Collectors.joining());

除了创建流的开销之外,它在内存使用方面应该与@Jacob的解决方案类似,因为
Collectors.joining()
在内部使用
StringBuilder

使用
StringBuilder
有效地部分构建
String
。如果您手头已有此信息,您可以告诉它一个初始缓冲区大小。您能给我们一个您正在做的代码示例吗?这样会更容易理解。
StringBuilder
仍然不是这是最好的方法。任何其他算法都将等同于相同的方法。(不要使用
StringBuffer
,使用
StringBuilder
)有一个输入错误:我的意思是
StringBuilder
而不是
StringBuffer
。我使用了一个
StringBuilder
,在
ArrayList
上有一个简单的
循环。所以我使用了3倍的空间(1x-用于初始
ArrayList
,2x-用于
StringBuilder
,3x-当调用
sb.toString()
有效地创建了一个返回
新字符串(值,0,计数);
)不包含子列表(int-fromIndex,int-toIndex){返回新的子列表(this,fromIndex,toIndex);}创建新对象?不要忘记JVM的优化器可能具有与字符串构建相关的技巧,这些技巧可能会使任何精心设计的Java端优化尝试无效,甚至会产生效果。顺便说一句,由于您的第二个变体无论如何都是手动处理列表索引,因此它甚至可以在wirthout
子列表
中工作。
Map<Integer, String> result = IntStream.range(0, 500).boxed()
            .collect(Collectors.groupingBy(
                    i -> i / 100,
                    Collectors.mapping(strings::get, Collectors.joining())));