17

This must have been asked before, but I'm afraid I can't find the answer.

In R, I can write

paste0('s', 1:10)

which returns a list of 10 character (string) variables:

[1] "s1"  "s2"  "s3"  "s4"  "s5"  "s6"  "s7"  "s8"  "s9"  "s10"

How do I do this simply in Python? The only way I can think of is with a for loop, but there must be a simple one-liner.

I've tried things like

's' + str(np.arange(10))
['s', str(np.arange(10))]
tsawallis
  • 1,035
  • 4
  • 13
  • 26
  • I'm very grateful that there is no equivalent. What do you think the output of `paste(1:2,1:3)` will be or of `paste("a", character(0))`? – jan-glx Jul 10 '20 at 13:49

5 Answers5

22
>>> ["s" + str(i) for i in xrange(1,11)]
['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10']

EDIT: range works in both Python 2 and Python 3, but in Python 2 xrange is a little more efficient potentially (it's a generator not a list). Thansk @ytu

cdyson37
  • 7,828
  • 3
  • 24
  • 16
  • Thanks! I wasn't sure whether to accept this answer or @jamylak's. Both seem nice to me. – tsawallis Jan 20 '15 at 16:08
  • It seems like that in Python 3 there's no `xrange` function. `["s" + str(i) for i in range(1,11)]` works just fine but `["s" + str(i) for i in xrange(1,11)]` gives a _NameError: name 'xrange' is not defined_. – ytu Jan 07 '18 at 03:26
  • @cdyson, could there be multiple `+` in this kind of function, like the `paste0` in R in which you can paste whatever many items you want together, like `paste0("a",1:10,11:20)`? – Jia Gao Jun 02 '18 at 02:47
  • You could use `zip` to accomplish things like that. How about `["".join (map (str, x)) for x in zip (["a"]*10, range(1,11), range(11,21))]` (Python3). We have to make 10 `"a"`s manually (zip won't just repeat them for you), then each x becomes a tuple e.g. `("a", 1, 1)` then we turn them into a list of strings with `map (str, x)`, then finally `"".join ()` is used to concatenate them. – cdyson37 Jun 03 '18 at 08:18
9
>>> list(map('s{}'.format, range(1, 11)))
['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10']
jamylak
  • 128,818
  • 30
  • 231
  • 230
5

The answer by cdyson37 is the most pythonic one; of course you can still use range rather than xrange in your case.

In Python2, you can also put more emphasis on functional style with something like:

map(lambda x: "s"+str(x), range(1,11))
Thomas Baruchel
  • 7,236
  • 2
  • 27
  • 46
0

None of these answers generalizes to arbitrary numbers of arguments like paste in R does. Here is a fairly faithful port of the original R function. The only thing to remember is that each element must be presented as a list, since character strings in R are actually just vectors of characters under the hood:

import itertools

def paste(*args, sep = ' ', collapse = None):
    """
    Port of paste from R
    Args:
        *args: lists to be combined
        sep: a string to separate the terms
        collapse: an optional string to separate the results
    Returns:
        A list of combined results or a string of combined results if collapse is not None
    """
    combs = list(itertools.product(*args))
    out = [sep.join(str(j) for j in i) for i in combs]
    if collapse is not None:
        out = collapse.join(out)
    return out

Usage:

paste (['s'], range(10), sep = '')
Out[62]: ['s0', 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9']
paste (['s'], range(2), ['t'], range(3), sep = '')
Out[63]: ['s0t0', 's0t1', 's0t2', 's1t0', 's1t1', 's1t2']
paste (['s'], range(2), ['t'], range(3), sep = '', collapse = ':')
Out[64]: 's0t0:s0t1:s0t2:s1t0:s1t1:s1t2'

You can get paste0 by using currying:

from functools import partial

paste0 = partial(paste, sep = '')
dspringate
  • 1,805
  • 2
  • 13
  • 20
  • Your function does something else if more than one argument is of length larger than 1 since you use `itertools.product` – jan-glx Jul 10 '20 at 13:18
0

This is a bit closer to R's paste (including it's quirk of recycling arguments with length other than 1:

def paste(*args, sep = " ", collapse = None):
    l = [list(arg) if isinstance(arg, str) else arg if hasattr(arg, '__len__') else list(str(arg)) for arg in args]
    l = list(itertools.islice((sep.join(parts) for parts in zip(*(itertools.cycle(map(str, e)) for e in l))), (max((len(x) for x in l)))))
    if collapse is not None:
        l = collapse.join(l)
    return l
paste(["a", "b"], range(2), "!")
# ['a 0 !', 'b 1 !']
jan-glx
  • 7,611
  • 2
  • 43
  • 63