编写一个函数,用*替换字符串第一个字母的每个重复字符除了第一个字母本身 - 是否有更多的pythonic /优雅方式来做这个(列表等?)?
def specialreplace(s):
firstchar = s[0]
modifiedstr = s[1:].replace(firstchar, "*")
print firstchar + modifiedstr
specialreplace('oompaloompa') ---> o*mpal**mpa
答案 0 :(得分:5)
这是一个简单的问题,我不确定你为什么要试图让它复杂化。你的解决方案看起来不错,除了你应该使用.join()而不是' +'将字符串连接在一起。
"".join((s[0], s[1:].replace(s[0], "*"))
答案 1 :(得分:2)
这不是推荐的方法,除非你反复这样做(对于每个字母,多次),但另一种方法是这样做:
我的速度错了。在Python3中也有所不同。
import string
a = 'ababc'
firstchar = a[0]
trantab = string.maketrans(firstchar, '*')
def translate(mystr, firschar):
trantab = string.maketrans(firstchar, '*')
return firstchar + string.translate(mystr[1:], trantab)
def translate_iter(mystr, firschar, trantab):
return firstchar + string.translate(mystr[1:], trantab)
def replace(mystr, firstchar):
return firstchar + mystr[1:].replace(firstchar, '*')
In [29]: %timeit translate(a, firstchar)
1000000 loops, best of 3: 582 ns per loop
In [30]: %timeit replace(a, firstchar)
1000000 loops, best of 3: 240 ns per loop
In [32]: %timeit translate_iter(a, firstchar, trantab)
1000000 loops, best of 3: 376 ns per loop
编辑:不要在字符串上使用连接。没有理由。
import dis
In [36]: def add(a,b):
return a+b
....:
In [37]: def join(a,b):
return join((a,b))
....:
In [42]: dis.dis(add)
2 0 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
6 BINARY_ADD
7 RETURN_VALUE
In [43]: dis.dis(join)
2 0 LOAD_GLOBAL 0 (join)
3 LOAD_FAST 0 (a)
6 LOAD_FAST 1 (b)
9 BUILD_TUPLE 2
12 CALL_FUNCTION 1
15 RETURN_VALUE
您正在招致无意义的函数调用,这使得代码的可读性降低,整体性能降低。
我为牺牲可读性而牺牲了性能,但是当它牺牲性能和可读性时却没有。
答案 2 :(得分:2)
您可以使用枚举:
print("".join(["*" if s[i] == s[0] and i != 0 else ch for i, ch in enumerate(s)]))
但这只是为了好玩,我会坚持使用你自己的解决方案。
要回答您的评论,您可以使用多个映射来使用translate替换多个字符:
from string import maketrans
print(s[0]+s[1:].translate(maketrans(s[0]+s[2]+s[3],"*$!")))
o*$!al**$!a
在python3中,你需要一个使用每个字符的ord作为键的表:
print(s[0]+s[1:].translate((dict(zip((ord(s[0]),ord(s[2]),ord(s[3])),"*$!")))))
o*$!al**$!a
你也可以使用re.sub忽略第一个字符:
s = 'oompaloompa'
from re import sub
print(sub(r"(?<!^)"+s[0], "*", s))
o*mpal**mpa
但又有点矫枉过正。
答案 3 :(得分:1)
您已经在使用列表索引和切片,并且您有一个干净的答案。仍然:
def specialreplace(s):
chars = [ ('*' if c == s[0] else c) for c in s[1:] ]
print s[0] + ''.join(chars)
如果你想编写一下这个代码:
specialreplace = lambda s:s[0]+''.join(['*'if c==s[0]else c for c in s[1:]])
使用铲除字典查找并使用默认返回值进行编辑,因为为什么不使用厨房水槽:
specialreplace=lambda s:s[0]+''.join([{s[0]:'*'}.get(c,c)for c in s[1:]])
编辑:@Voo的评论,列表理解是合理的Pythonic - 如果你必须使用SpicyClubSauce所要求的字符列表,那么你就像Python一样接近三元运算符,并加入一个连接字符列表重新组合在一起。 lambda版本非常不顺便。所有这些都不如提问者的原始解决方案那么优雅。
答案 4 :(得分:1)
您的代码看起来很好,我认为可以改进它的一种方法是获得多个索引,为此您可以使用iter
函数将字符串转换为支持{{1}的迭代器}:
next
另外,您可以使用列表推导和>>> def specialreplace(s):
... it=iter(s)
... first=next(it)
... return first+''.join(it).replace(first,'*')
...
>>> specialreplace(s)
'o*mpal**mpa'
替换replace
方法:
join
以下基准测试表明它们之间没有太大区别,但第二种方法更好一点。(对于1000000循环而不是长字符串测试)
def specialreplace(s):
it=iter(s)
first=next(it)
return first+''.join(['*' if i == first else i for i in it])
结果:
from timeit import timeit
s1="""
def specialreplace(s):
firstchar = s[0]
modifiedstr = s[1:].replace(firstchar, "*")
print firstchar + modifiedstr
"""
s2="""
def specialreplace(s):
it=iter(s)
first=next(it)
return first+''.join(['*' if i == first else i for i in it])
"""
s3="""
def specialreplace(s):
it=iter(s)
first=next(it)
return first+''.join(it).replace(first,'*')
"""
print ' first: ' ,timeit(stmt=s1, number=1000000)
print 'second : ',timeit(stmt=s2, number=1000000)
print '3rd : ',timeit(stmt=s3, number=1000000)
答案 5 :(得分:0)
这是使用str.replace()
方法执行此操作的pythonic方法:
string_ = 'oompaloompa'
new_string = string_[0]+string_.replace(string_[0],"*",string_.count(string_[0]))[1:
答案 6 :(得分:0)
Drawable drawable
if(needBlue){
drawable = getResources().getDrawable(R.drawable.spin_shape_blue);
}else{
drawable = getResources().getDrawable(R.drawable.spin_shape_orange);
}
imageView.setImageDrawable(drawable);
答案 7 :(得分:0)
class Coupon(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
code = models.CharField(max_length=20)
amount = models.FloatField(max_length=4)
valid_from = models.DateTimeField(null=True)
valid_to = models.DateTimeField(null=True)
max_value = models.IntegerField(validators=[MaxValueValidator(100)], verbose_name='Coupon Quantity', null=True)
used = models.IntegerField(default=0)