Say I've got an ArrayList<String>
of size 500 and then I want to effectively concat strings with indexes (starting from 1): 1-100, 101-200, ..., 401-500 strings (so I want to get 5 strings instead of 500). I thought I could use StringBuilder
and then use .toString
but .toString()
method of StringBuilder
creates a new string, so effectively I'll create 5 * 2 = 10
strings which is bad (these strings are really huge and I'm short of space). What is the most best memory & time efficient way to do this?
What I've tried so far:
There's a typo: I meant StringBuilder
instead of StringBuffer
. I used a StringBuilder
with a straightforward for
loop over this ArrayList<String>
. So I used 3x space (1x - for initial ArrayList
, 2x - for StringBuilder
, 3x - when call sb.toString()
which effectively create a returns new String(value, 0, count);
)
One option would be to use List#subList
(as that's just a view of the List
and shouldn't use any more memory). You can then call String#join
on it:
String.join(" " /*Delimiter*/, list.subList(0, 100 /*Exclusive*/));
Just throw this inside of a for-loop and store each String
to an index of a String[]
and you're good to go!
By popular demand, here's an alternate solution that is potentially more efficient, but would have to be properly bench-marked with 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();
}
It can be improved if you know the sum of the lengths of each sub-list ahead of time, or replace the call to List#stream
with its own for-loop.