Strings in Python are immutable, and so 'string a' + 'string b' has to make a third string to combine them. Say you want to clone a string, by adding each item to the string will get \ time, as opposed to \
as you would get if it were a list.
And so, the best way to join an iterable by a separator is to use str.join.
>>> ','.join('abcdef')
'a,b,c,d,e,f'
If you want to do this manually, then I'd accept the \ performance, and write something easy to understand. One way to do this is to take the first item, and add a separator and an item every time after, such as:
def join(iterator, seperator):
it = map(str, iterator)
seperator = str(seperator)
string = next(it, '')
for s in it:
string += seperator + s
return string
Answer from Peilonrayz on Stack ExchangeStrings in Python are immutable, and so 'string a' + 'string b' has to make a third string to combine them. Say you want to clone a string, by adding each item to the string will get \ time, as opposed to \
as you would get if it were a list.
And so, the best way to join an iterable by a separator is to use str.join.
>>> ','.join('abcdef')
'a,b,c,d,e,f'
If you want to do this manually, then I'd accept the \ performance, and write something easy to understand. One way to do this is to take the first item, and add a separator and an item every time after, such as:
def join(iterator, seperator):
it = map(str, iterator)
seperator = str(seperator)
string = next(it, '')
for s in it:
string += seperator + s
return string
Let's take that step by step:
def join(l, sep):
out_str = ''
for i, el in enumerate(l):
Here, why do you need the enumerate? You could write for el in l:
out_str += '{}{}'.format(el, sep)
.format is not super efficient, there are other methods. You can have a look at This question for some researches and benchmarks on performances.
return out_str[:-len(sep)]
This makes little sense for l = [] if len(sep) > 1. ''[:-1] is valid, and returns '', because python is nice, but it is not a very good way of getting around that limit case.
In general, adding something just to remove it at the end is not great.
Creating an iter, looking at the first value, then adding the rest, as it has been suggested in other answers, is much better.
I would also recommend writing some unit tests, so that you can then play around with the implementation, and stay confident that what you write still works.
Typically, you could write:
# Empty list
join([], '') == ''
# Only one element, -> no separator in output
join(['a'], '-') == 'a'
# Empty separator
join(['a', 'b'], '') == 'ab'
# "Normal" case
join(['a', 'b'], '--') == 'a--b'
# ints
join([1, 2], 0) == '102'
python - How can I use str.join() instead of "+=" to join a list of strings with separator? - Stack Overflow
python - How to flatten a list of lists and join with a separator - Stack Overflow
python - How to concatenate (join) items in a list to a single string - Stack Overflow
python - join with a separator added at the end when not empty - Stack Overflow
If the separator is a variable you can just use variable.join(iterable):
data = ["some", "data", "lots", "of", "strings"]
separator = "."
print(separator.join(data))
some.data.lots.of.strings
output_string = ".".join(data)
if you have integers or non-strings in data, then
output_string = ".".join( str(x) for x in data )
For example your list is stored in x:
x=[[1,2], [3,4,5], [6,7]]
Simply use reduce with lambda function:
y=reduce(lambda a,b:a+[0]+b,x)
Now y is
[1, 2, 0, 3, 4, 5, 0, 6, 7]
Or you could define an generator function:
def chainwithseperator(lis,sep):
it=iter(lis)
for item in it.next():
yield item
for sublis in it:
yield sep
for item in sublis:
yield item
Now calling:
y=list(chainwithseperator(x,0))
Will bring you the same result
You can tee the list as an iterable and only yield the separator when there's a following item. Here we're defining a function called joinlist which contains a generator helper function to yield the appropriate elements, then returns a flattened list of all those elements using chain.from_iterable:
from itertools import tee, chain
def joinlist(iterable, sep):
def _yielder(iterable):
fst, snd = tee(iterable)
next(snd, [])
while True:
yield next(fst)
if next(snd, None):
yield [sep]
return list(chain.from_iterable(_yielder(iterable)))
It's important to note that the termination for the while True: occurs in yield next(fst) as that'll raise a StopIteration at some point and will cause the generator to exit.
Example:
x = [[1,2]]
y = [[1, 2], [3,4,5]]
z = [[1, 2], [3,4,5], [6, 7]]
for item in (x, y, z):
print item, '->', joinlist(item, 0)
# [[1, 2]] -> [1, 2]
# [[1, 2], [3, 4, 5]] -> [1, 2, 0, 3, 4, 5]
# [[1, 2], [3, 4, 5], [6, 7]] -> [1, 2, 0, 3, 4, 5, 0, 6, 7]
Use str.join:
Use with AI>>> words = ['this', 'is', 'a', 'sentence']
>>> '-'.join(words)
'this-is-a-sentence'
>>> ' '.join(words)
'this is a sentence'
A more generic way (covering also lists of numbers) to convert a list to a string would be:
Use with AI>>> my_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> my_lst_str = ''.join(map(str, my_lst))
>>> print(my_lst_str)
12345678910
I would go with this (updated to reflect edits to the question):
'.'.join([''] + args[f(n):f(n+1)] + [suffix])
EDIT: taking inspiration from sblom's and unutbu's answers, I might actually do this:
from itertools import chain, islice
string = '.'.join(chain([string], islice(args, f(n), f(n+1)), [suffix]))
if I were concerned about the memory cost of slicing args. You can use a tuple (string,) or a list [string] for the string and the suffix; given that they're one element each, there's no significant difference in memory usage or execution time, and since they're not being stored, you don't have to worry about mutability. I find the list syntax a little cleaner.
However: I'm not sure if Python actually creates a new list object for a slice that is only going to be used, not assigned to. If it doesn't, then given that args is a proper list, using islice over [f(n):f(n+1)]doesn't save you much of anything, and in that case I'd just go with the simple approach (up top). If args were a generator or other lazily evaluated iterable with a very large number of elements, then islice might be worth it.
If list_ is a generator (or can be trivially changed to be one), you can get away without materializing any lists at all using chain() from itertools.
from itertools import chain
'.'.join(chain(('',),list_,(suffix,)))
(This takes inspiration from David Zaslavsky's answer.)
There is no standard approach, but a natural way is to add empty strings at the end or at the beginning (or at the end and the beginning). Using some more modern syntax:
>>> ', '.join(['', *['a', 'b', 'c', 'd']])
', a, b, c, d'
>>> ', '.join([*['a', 'b', 'c', 'd'], ''])
'a, b, c, d, '
>>> ', '.join(['', *['a', 'b', 'c', 'd'], ''])
', a, b, c, d, '
Or just use string formatting:
>>> sep = ','
>>> data = ['a', 'b', 'c', 'd']
>>> f"{sep}{sep.join(data)}"
',a,b,c,d'
>>> f"{sep.join(data)}{sep}"
'a,b,c,d,'
>>> f"{sep}{sep.join(data)}{sep}"
',a,b,c,d,'
Here is the way:
list1 = ['1','2','3','4']
s = ","
r = f"{s}{s.join(list1)}"
p = f"{s.join(list1)}{s}"
q = f"{s}{s.join(list1)}{s}"
print(r)
print(p)
print(q)