Python, optimizing a list comprehension for string concatenation
Question: I'm using `cProfile` to run benchmarks on a script that process strings via
list comprehension. The target line I'd like to optimize looks like this:

    
    
    signals = [('prefix' + str(day) + '_' + s) for s in signals]
    

where `day` is an integer.

This particular line is using a whopping 33% of the entire run time. Of
course, it's called million of times during the execution.

I've tried a couple obvious alternatives, including `''.join('prefix',
str(day), '_', s)`, `'prefix{:}_'.format(day)`, and using
`numpy.core.defchararray.add` to concatenate a prefix array created via
`numpy.tile` with `signals`. They are both up to 2x slower than list
comprehension.

Is there still room for speed optimization for this line?


Answer: This should bring at least a minimum improvement:

    
    
    # First precalculate the static part of the string
    template = 'prefix%s_' % day + '%s'
    
    # Then, use the %s string interpolation instead of joining strings with '+'  
    # -->> Note: this proved to be wrong later... 
    signals = [template % s for s in signals]
    
    # Alternatively you could use map to compare efficiency (be aware of differences between python 2 and 3)
    signals = map(template.__mod__, signals)
    

The `str.format` is more expensive than the `%s` interpolation, so I am not
going to try it.

Now let's compare the timings. Your method:

    
    
    >>> import timeit
    >>> day = 45
    >>> signals = ['aaaa', 'bbbb', 'cccccc', 'dddddddddddd']
    >>> timeit.timeit("[('prefix' + str(day) + '_' + s) for s in signals]", 'from __main__ import day, signals')
    1.35095184709592
    

My first approach

    
    
    >>> template = 'prefix%s_' % day + '%s'
    >>> timeit.timeit("[template % s for s in signals]", 'from __main__ import template, signals')
    0.7075940089748229
    

My second approach

    
    
    >>> timeit.timeit("map(template.__mod__, signals)", 'from __main__ import template, signals')
    0.9939713030159822
    

So, the precalculation of the template with list comprehension seems to win.
There are further things to consider, as for example, if a generator is good
enough for you.

**EDIT** from info pointed out in the interesing comments, I add another
solution: inside of the tight loop we are only joining two strings together,
so we can concatenate them directly instead of %-formatting

    
    
    >>> template = 'prefix%s_' % day
    >>> timeit.timeit("[template + s for s in signals]", 'from __main__ import template, signals')
    0.39771016975851126
    

Which for the moment is the winner.

