0

Aim

I would like to generate a sequence as list in python, such as:

['s1a', 's1b', 's2a', 's2b', ..., 's10a', 's10b']

Properties:

  • items contain a single prefix
  • numbers are sorted numerical
  • suffix is alternating per number

Approach

To get this, I applied the following code, using an xrange and comprehensive list approach:

# prefix
p = 's'
# suffix
s = ['a', 'b']
# numbers
n = [ i + 1 for i in list(xrange(10))]
# result
[ p + str(i) + j for i, j in zip(sorted(n * len(s)), s * len(n)) ]

Question

Is there a more simple syntax to obtain the results, e.g. using itertools? Similar to this question?

Community
  • 1
  • 1
setempler
  • 1,681
  • 12
  • 20
  • FWIW, `sorted(n * len(s))` is an inefficient way to create that list, it would be better to do the replication inside the list comprehension that creates `n`. Also, `list(xrange(...))` is an anti-pattern: if you want an actual list, just use `range`. (Of course, in Python 3, `range` returns a range object, not a list, so you _do_ have to wrap it in a `list` call when you want an actual list). – PM 2Ring Feb 03 '17 at 12:12

5 Answers5

5

A doubled-for list comprehension can accomplish this:

['s'+str(x)+y for x in range(1,11) for y in 'ab']
James
  • 32,991
  • 4
  • 47
  • 70
  • I count the usage of *doubled* list comprehension, as well as `range` instead `xrange` as improvement. Will accept answer in case no better solutions are found. Thanks. – setempler Feb 03 '17 at 11:52
  • 1
    @setempler: using `range` also makes it compatible with Python 3. :) – James Feb 03 '17 at 11:56
3

itertools.product might be your friend:

all_combos = ["".join(map(str, x)) for x in itertools.product(p, n, s)]

returns:

['s1a', 's1b', 's2a', 's2b', 's3a', 's3b', 's4a', 's4b', 's5a', 's5b', 's6a', 's6b', 's7a', 's7b', 's8a', 's8b', 's9a', 's9b', 's10a', 's10b']

EDIT: as a one-liner:

all_combos = ["".join(map(str,x)) for x in itertools.product(['s'], range(1, 11), ['a', 'b'])]

EDIT 2: as pointed out in James' answer, we can change our listed string element in the product call to just strings, and itertools will still be able to iterate over them, selecting characters from each:

all_combos = ["".join(map(str,x)) for x in itertools.product('s', range(1, 11), 'ab')]
asongtoruin
  • 9,794
  • 3
  • 36
  • 47
1

How about:

def func(prefix,suffixes,size):
    k = len(suffixes)
    return [prefix+str(n/k+1)+suffixes[n%k] for n in range(size*k)]

# usage example:
print func('s',['a','b'],10)

This way you can alternate as many suffixes as you want.

And of course, each one of the suffixes can be as long as you want.

barak manos
  • 29,648
  • 10
  • 62
  • 114
  • A function was not my intention to use, but the `return` statement clearly yields an interesting approach to generalise the method. – setempler Feb 03 '17 at 11:58
0

You can use a double-list comprehension, where you iterate on number and suffix. You don't need to load any

Below is a lambda function that takes 3 parameters, a prefix, a number of iterations, and a list of suffixes

foo = lambda prefix,n,suffix: list(prefix+str(i)+s for s in suffix for i in range(n))

You can use it like this

foo('p',10,'abc')

Or like that, if your suffixes have more than one letter

foo('p',10,('a','bc','de'))
Guillaume Jacquenot
  • 11,217
  • 6
  • 43
  • 49
  • 2
    `lambda` is for creating anonymous functions, so it's generally considered bad style to bind a `lambda` to a name. If you want to write a named function you should use the proper `def` syntax. – PM 2Ring Feb 03 '17 at 11:59
0

For maximum versatility I would do this as a generator. That way you can either create a list, or just produce the sequence items as they are needed.

Here's code that runs on Python 2 or Python 3.

def psrange(prefix, suffix, high):
    return ('%s%d%s' % (prefix, i, s) for i in range(1, 1 + high) for s in suffix)

res = list(psrange('s', ('a', 'b'), 10))
print(res)

for s in psrange('x', 'abc', 3):
    print(s)

output

['s1a', 's1b', 's2a', 's2b', 's3a', 's3b', 's4a', 's4b', 's5a', 's5b', 's6a', 's6b', 's7a', 's7b', 's8a', 's8b', 's9a', 's9b', 's10a', 's10b']
x1a
x1b
x1c
x2a
x2b
x2c
x3a
x3b
x3c
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182