我正在实现类似于Python的join函数的功能,其中

join([a1, a2, ..., aN], separator :: String)


返回

str(a1) + separator + str(a2) + separator + ... + str(aN)


例如,

join([1, 2, 3], '+') == '1+2+3'



我正在实现类似的功能,并且想知道执行此操作的最佳模式是什么?因为存在仅在分隔符不是最后一个元素时才添加分隔符的问题。

def join(l, sep):
    out_str = ''
    for i, el in enumerate(l):
        out_str += '{}{}'.format(el, sep)
    return out_str[:-len(sep)]


我对此很满意,但是有没有规范的方法? br />

评论

在Perl的联接中,分隔符是避免歧义的第一个参数。

好的,通常在大多数语言和实现中,迭代地添加N个任意字符串将是O(N ^ 2),因为在每个循环中都需要调用malloc / realloc(),但是cPython对此有特殊情况,所以它只有N * O( 1)= O(N)。在本机Python中。 string.join或sep.join更快,因为它们是一个Python调用,而不是N。请参阅迭代字符串附加的时间复杂性实际上是O(n ^ 2)还是O(n)?

我比分隔符更喜欢定界符

@ bhathiya-perera“定界符”比“分隔符”更宽泛,也是技术术语。

#1 楼

Python中的字符串是不可变的,因此'string a' + 'string b'必须制作第三个字符串以将它们组合在一起。假设您要克隆一个字符串,通过将每个项目添加到字符串中将获得\ $ O(n ^ 2)\ $时间,而不是\ $ O(n)\ $(如果它是一个列表)。

因此,使用分隔符连接迭代器的最佳方法是使用str.join

>>> ','.join('abcdef')
'a,b,c,d,e,f'



如果需要手动执行此操作,那么我会接受\ $ O(n ^ 2)\ $性能,并编写一些易于理解的内容。一种方法是获取第一个项目,并在每次之后添加一个分隔符和一个项目,例如:

def join(iterator, seperator):
    it = map(str, iterator)
    seperator = str(seperator)
    string = next(it, '')
    for s in it:
        string += seperator + s
    return string


评论


\ $ \ begingroup \ $
非常好,谢谢!是的,我对str.join有所了解,我只是在实现一些稍有不同的东西,并且想知道如何更好地做到这一点。我喜欢您在开始时使用next的方法!你知道我在哪里可以找到str.join的来源吗? Google没有帮助。
\ $ \ endgroup \ $
–fabian789
17年5月8日在11:28

\ $ \ begingroup \ $
@ fabian789 str.join的来源可能是这样。它看起来正确,并用C编写。
\ $ \ endgroup \ $
– Peilonrayz
17年5月8日在11:44



#2 楼

让我们逐步进行操作:

def join(l, sep):
    out_str = ''
    for i, el in enumerate(l):


这里,为什么需要enumerate?您可以编写for el in l:

        out_str += '{}{}'.format(el, sep)


.format不是超级有效,还有其他方法。您可以看一下该问题,以获取有关性能的一些研究和基准。

    return out_str[:-len(sep)]


如果l = []len(sep) > 1没有意义。 ''[:-1]是有效的,并返回'',因为python很不错,但它不是解决该限制情况的一种很好的方法。太好了。

创建一个iter,先看第一个值,然后再添加其余值(如在其他答案中建议的那样)会更好。

我也建议编写一些单元测试,以便您可以进行实施,并确信自己编写的内容仍然有效。

通常,您可以编写: br />

#3 楼

您可以通过多种方法来执行此操作,但是使用迭代器可能是一种不错的方法:

在使用next()循环遍历其余部分之前,它与iterable的第一项有所不同。

评论


\ $ \ begingroup \ $
试试[]
\ $ \ endgroup \ $
– njzk2
17年5月8日在15:58

#4 楼

由于join已经是Python的内置函数,因此建议不要创建名称相同的函数。我认为将函数重命名以排除可能的冲突是个好主意。

评论


\ $ \ begingroup \ $
这只是错误的,help(join)导致NameError:未定义名称'join'。现在help(str.join)存在,但这不会引起任何冲突。
\ $ \ endgroup \ $
– Peilonrayz
20年7月8日在8:58



\ $ \ begingroup \ $
“由于join已经是Python的内置函数,建议不要创建一个同名的函数”-这也不适用于OP要求的上下文。这就是为什么他们首先添加“ reinvent-the-wheel”标签的原因:)
\ $ \ endgroup \ $
– Grajdeanu Alex
20年7月8日在9:31