我想得到一个字符串最大出现的第一个字母。
例如:
"google" -> g
"azerty" -> a
"bbbaaa" -> b
我已经有了一个有效的代码,使用OrdererDict()来避免自动重新排列:
from collections import OrderedDict
sentence = "google"
d = OrderedDict()
for letter in sentence:
if letter not in d.keys():
d[letter] = sentence.count(letter)
print(max(d, key=d.get)) # g
但我正在寻找一种可能的单行或更优雅的解决方案(如果可能的话)。
注意: 我已经尝试使用Counter()但它不起作用,因为python中的dict不记得键被插入的顺序。
e.g
from collections import Counter
sentence = "bbbaaa"
c = Counter(sentence)
print(c.most_common()[0][0]) # have 50% chances of printing 'a' rather than 'b'.
奖金问题:有人可以解释为什么OrderedDict()不是python中的默认字典行为吗?
答案 0 :(得分:6)
collections.OrderedDict
的文档实际上有a recipe for an OrderedCounter
:
In [5]: from collections import Counter, OrderedDict
In [6]: class OrderedCounter(Counter, OrderedDict):
...: pass
...:
In [7]: OrderedCounter("google").most_common()[0][0]
Out[7]: 'g'
答案 1 :(得分:5)
可能不是很快,但是单行!
>>> s = "aaabbbbc"
>>> sorted(s, key=lambda c: (-s.count(c), s.index(c)))[0]
'b'
修改强>
甚至更短,感谢@Ohad Eytan的评论:
>>> min(s, key=lambda c: (-s.count(c), s.index(c)))
'b'
<强>基准强>
今晚感到无聊,所以我进行了基准测试(使用timeit
)测试@Joohwan的most_common_char()
解决方案(mostcc),@ Blender的OrderedCounter
解决方案(odict)和我自己的单线解决方案(onelin) ,使用min
变体)。最快的解决方案始终是mostcc:对于包含少量不同字符的长字符串,比onelin快~10倍,对于非常短的字符串,比odict快4倍。对于具有少量重复字符的短字符串或字符串,onelin击败odict(否则,它是相反的)。以下是详细信息(长度=字符串的长度,#chars =从每个字符中随机选择的不同unicode字符的数量,mostcc =执行10,000次mostcc的时间,odict =与mostcc相比多长的odict,onelin =与大多数人相比,线上多久了。
Length #chars mostcc odict onelin
10 10: 0.08s 3.76x 1.61x
10 100: 0.10s 3.57x 1.27x
10 1000: 0.12s 3.12x 1.34x
100 10: 0.43s 1.96x 3.29x
100 100: 0.59s 2.16x 2.18x
100 1000: 0.80s 1.92x 1.72x
1000 10: 3.48s 1.56x 9.79x
1000 100: 3.44s 1.72x 6.43x
1000 1000: 6.55s 1.68x 3.30x
答案 2 :(得分:3)
我知道你想要一个单行,但是如果你不得不多次重复这个任务或处理很长的句子怎么办?我不知道确切的用例,但考虑到算法的空间和时间复杂性,您可能值得花时间。
例如,在您的解决方案中,您使用sentence.count()
对句子进行了多次迭代,而O(n * number of unique characters)
需要O(number of unique characters)
。之后,再次遍历ordereddict以找到max(另一个from collections import defaultdict
def most_common_char(sentence):
if not sentence:
return ''
max_count = 1
max_char = sentence[-1]
char_counts = defaultdict(int)
char_counts[max_char] = 1
for i in xrange(len(sentence) - 2, -1, -1):
char = sentence[i]
char_counts[char] += 1
if char_counts[char] >= max_count:
max_count = char_counts[char]
max_char = char
return max_char
操作)。
在公认的解决方案中,我们最终必须定义一个新类(它打破你的1个班轮要求btw)并实例化新对象,其中包含很多样板代码和功能,你可能每次都不需要执行你的任务。
如果您不介意再添几行代码(再次,我知道这不是问题所在),我们可以构建一个可重用的函数,只需迭代字符串一次并使用恒定和最小的空间:
const uint8_t test123Array[64] = {
0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
我们跟踪字符的最大数量为我们通过字符串并在迭代结束时将其吐出。请注意,我们向前迭代 ,因为您需要首先出现的字母(即最后更新的胜利)。
答案 3 :(得分:2)
您可以Counter()
与next()
一起使用来查找符合条件的第一个字母:
>>> s = "google"
>>> c = Counter(s)
>>> next(x for x in s if c[x] == c.most_common(1)[0][1])
'g'
答案 4 :(得分:1)
您还可以通过使用各种属性对结果列表进行排序来修复您在问题结尾处描述的有关使用Counter的问题:首先计算,其次是字典顺序,如下所示:
=> [('g', 2), ('o', 2), ('l', 1), ('e', 1)]
输出:
# If your sentence is s:
print(sorted(collections.Counter(s).most_common(),key=lambda x:(-x[1],s.index(x[0]))))
只是为了好玩:
高尔夫版本:
/cygdrive/c