5

How can I cycle through a list of delimiters in my string?

I'm trying to reference this post but am not following if enumerate is a correct approach.

my_list = range(11, 17)
# formats = ['#', '$', '%']
# How to implement formats?
my_string = '#'.join(map(str, my_list))
my_string

# have: '11#12#13#14#15#16'
# want: '11#12$13%14#15$16'
md2614
  • 353
  • 2
  • 14

2 Answers2

4

You could use itertools.cycle combined with zip:

from itertools import cycle

my_list = range(11, 17)
formats = cycle(['#', '$', '%'])

''.join(str(a) + b for a, b in zip(my_list, formats))

This produces '11#12$13%14#15$16%'. Notice the trailing % character.. you could drop that one manually, e.g. by slicing up to -1:

''.join(str(a) + b for a, b in zip(my_list, formats))[:-1]

By the way, if this is something you encounter a lot in your codebase, you might write a helper class, e.g.

from itertools import cycle


class MultiDelimiter:
    def __init__(self, *delimiters):
        self.delimiters = delimiters
        
    def join(self, strings):
        joined = ''.join(s + d for s, d in zip(strings, cycle(self.delimiters)))
        return joined[:-1]
    
            
my_list = ['11', '12', '13', '14', '15', '16']
            
delim = MultiDelimiter('#', '$', '%')
delim.join(my_list)  # returns: "11#12$13%14#15$16"

This uses the same convention as string.join, which helps in code readability / maintenance.

Kris
  • 22,079
  • 3
  • 30
  • 35
1

You can use mod 3 (i%3) to find out which index value you need to concat with. Here I am doing it using mod 3 as the length of formats is 3.

Here's the implementation.

my_list = range(11, 17)
formats = ['#', '$', '%']
mystring = ''.join(str(i)+formats[(i+1)%3] for i in my_list)[:-1]
print (mystring)

Since we are using join, it concats the last range number as well. So we need to exclude the last position. To do that i am using [:-1]

Output for this is:

11#12$13%14#15$16

If you want to make it generic, you can do this:

mystring = ''.join(str(j)+formats[i%len(formats)] for i,j in enumerate(my_list))[:-1]

Here's the results for the following ranges:

formats = ['#', '$', '%']
my_list = range(11, 25)

11#12$13%14#15$16%17#18$19%20#21$22%23#24

formats = ['#', '$', '%']
my_list = range(12, 25)

12#13$14%15#16$17%18#19$20%21#22$23%24

formats = ['#', '$', '%']
my_list = range(13, 25)

13#14$15%16#17$18%19#20$21%22#23$24

formats = ['#', '$', '%']
my_list = range(14, 25)

14#15$16%17#18$19%20#21$22%23#24

formats = ['#', '$', '%']
my_list = range(15, 25)

15#16$17%18#19$20%21#22$23%24

my_list = range(11, 25)
formats = ['#', '$', '%', '&','@']

11#12$13%14&15@16#17$18%19&20@21#22$23%24

my_list = range(12, 25)
formats = ['#', '$', '%', '&']

12#13$14%15&16#17$18%19&20#21$22%23&24

Let me know if the generic code fails on any condition.

Joe Ferndz
  • 8,417
  • 2
  • 13
  • 33
  • Fails for example `my_list = ['foo', 'bar']` with `formats = [' and ']`, producing `'foo and bar and'` instead of `'foo and bar'`. – Kelly Bundy Feb 07 '21 at 12:34