max
max

Reputation: 52293

join with a separator added at the end when not empty

I need to append all elements in list_ to a string; at the end I need to add a suffix. A dot '.' has to separate all elements:

list_ = args[f(n) : f(n+1)]
if list_:
  string += '.' + '.'.join(list_) + '.' + suffix # works except when list_ is empty
else:
  string += '.' + suffix
# list_ isn't used after this

Can I rewrite it in a simpler way in one line? If join added a separator after each element, it would just this:

string += '.' + '.'.join(args[f(n) : f(n+1)]) + '.' + suffix

Edit

I just learned that:

Slices are copies even if they are never assigned to: Does Python do slice-by-reference on strings?

But islice may be even worse since it iterates through the start of the list: itertools.islice compared to list slice

Some alternatives are discussed here: Avoiding unnecessary slice copying in Python

Upvotes: 3

Views: 16177

Answers (4)

David Z
David Z

Reputation: 131610

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.

Upvotes: 5

unutbu
unutbu

Reputation: 879919

Also riffing on David Zaslavsky answer:

string = '.'.join([string] + list_ + [suffix])

The advantage of doing it this way is that there is no addition of strings.

Upvotes: 4

sblom
sblom

Reputation: 27343

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.)

Upvotes: 4

JBernardo
JBernardo

Reputation: 33407

string += ('.' + '.'.join(list_) if list_ else '') + '.' + suffix 

Upvotes: 1

Related Questions