连接非空字符串并在末尾添加分隔符

3
我需要将list_中的所有元素添加到一个string中,最后需要添加一个后缀。一个点'.'必须分隔所有元素:
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

我能不能简单地用一行话来重写它?如果 join 在每个元素后面添加一个分隔符,那么它就是这样的:

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

编辑

我刚学到:

即使从未分配,切片也是副本:Python在字符串上进行切片引用吗?

但islice可能更糟,因为它遍历列表的开头:itertools.islice与list slice比较

这里讨论了一些替代方案:在Python中避免不必要的切片复制

4个回答

5
我建议采用以下内容(已更新以反映对问题的编辑):
'.'.join([''] + args[f(n):f(n+1)] + [suffix])

编辑: 受sblom和unutbu答案的启发,我可能会实际上这样做:

from itertools import chain, islice
string = '.'.join(chain([string],  islice(args, f(n), f(n+1)), [suffix]))

如果我担心对args进行切片的内存开销,你可以使用一个包含字符串和后缀的元组(string,)或列表[string]; 鉴于它们只有一个元素,内存使用和执行时间没有显著的差异,并且由于它们没有被存储,所以你不必担心可变性。我认为列表语法更加简洁。
然而:我不确定Python是否会为仅将用于使用而不是赋值的切片创建新的列表对象。如果它不这样做,那么,鉴于args是一个合适的列表,使用islice覆盖[f(n):f(n+1)]并不能节省太多东西,在这种情况下,我会选择简单的方法(在顶部)。如果args是一个生成器或其他懒惰地求值的可迭代对象,并且具有非常大量的元素,那么islice可能是值得的。

4

如果list_是生成器(或者可以轻松地改为生成器),您可以使用itertools中的chain()而不需要使任何列表材料化。

from itertools import chain
'.'.join(chain(('',),list_,(suffix,)))

(这受到David Zaslavsky答案的启发。)

我喜欢这种方法,但我不确定是否容易创建一个生成器来返回现有列表的切片? - max
当然,你可以使用 itertools.islice(list_, f(n), f(n+1)) - David Z
@DavidZaslavsky:根据我所了解的(请参见问题的更新),islice在列表上的性能非常差...如果我有一个真正的生成器,我会使用这种方法。 - max

4

还有基于David Zaslavsky的回答的改进:

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

这样做的优点在于没有字符串拼接,详情请参见此处

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

抱歉,忘记提到list_实际上是一个表达式;我希望避免为它创建额外的变量(请参见我的问题更新)。 - max
好的,你已经在你的代码中这样做了...如果你不介意创建2个额外的列表,那就使用David的代码吧。 - JBernardo
是的,在我的情况下,这不是性能问题,只是让代码看起来简单。 - max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接