Search code examples
javajava-8stringbuilder

How do I effectively concat consecutive interval of strings from ArrayList in Java?


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);)


Solution

  • 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.