如何解决使用python解决这个问题的最佳方法
我是 Python 新手,正在练习一些问题。无法针对以下问题优化我的解决方案。
问题陈述:根据词频对句子中的词进行编码,并返回它们的排名和词的编码值。
示例: 输入字符串 --> 'aaa bb ccc aaa bbb bb cc ccc ccc bb ccc bbb'
预期输出 --> 3|2|1|3|4|2|5|1|1|2|1|4
说明:-因为'aaa'在原始字符串中出现了2次,'ccc'出现了4次,'bb'出现了3次,因此它们根据频率进行排名。以这种方式,'ccc' 等级为 1,'bb' 等级为 2,'ccc' 等级为 3。因此结果如上所述。
下面是我的python代码,但是无法优化。有人可以帮忙吗。
def testing(s):
ht = {}
new_strs = strs.split()
print(new_strs)
for i in new_strs:
if i in ht:
ht[i] += 1
else:
ht[i] = 1
print(ht)
temp = list(map(list,sorted(ht.items(),key=lambda v: v[1],reverse=True)))
print(temp)
for k,v in enumerate(temp):
temp[k].append(k+1)
print(temp)
final = []
for j in new_strs:
for t in temp:
if t[0] == j:
final.append(str(t[2]))
return '|'.join(final)
strs = 'aaa bb ccc aaa bbb bb cc ccc ccc bb ccc bbb'
result = testing(str)
print(result)
下面是我从这段代码中得到的结果。
['aaa','bb','ccc','aaa','bbb','cc','bbb']
{'aaa': 2,'bb': 3,'ccc': 4,'bbb': 2,'cc': 1}
[['ccc',4],['bb',3],['aaa',2],['bbb',['cc',1]]
[['ccc',4,1],3,2,1,5]]
3|2|1|3|4|2|5|1|1|2|1|4
预先感谢您的帮助。
解决方法
您的代码通过计数没有问题。从您的 for j
循环开始,我完全不确定您认为这应该如何工作。
您需要遍历字符串中的给定单词——一个循环,不是嵌套循环。 对于输入中的每个单词,将其频率放入结果中。
for word in new_strs:
final.append(str(ht[word]))
print(final)
有了这个替换,你的输出是:
['2','3','4','2','1','2']
2|3|4|2|2|3|1|4|4|3|4|2
正如 Robert
已经指出的那样,您的代码中还有其他错误。特别是,您将 type 传递到您的函数中。如果您希望 str
成为一个变量,不要那样做。当您使用 Python 定义的名称(字符串类型)作为变量时,您会损坏您的名称空间,并且会发生奇怪的事情。
这有点令人费解,但可以做到。
我认为这是最好的方法,即将排名逻辑分成一个类。
from collections import Counter
class Ranker:
def __init__(self,items):
self._item_counts = Counter(items)
self._ranks = list(set(i[1] for i in Counter(items).most_common()))[::-1]
def __getitem__(self,item):
return self._ranks.index(self._item_counts[item]) + 1
if __name__ == '__main__':
strs = 'aaa bb ccc aaa bbb bb cc ccc ccc bb ccc bbb aaa'.split()
r = Ranker(strs)
print('|'.join([str(r[s]) for s in strs]))
# 2|2|1|2|3|2|4|1|1|2|1|3|2
,
正如评论中指出的那样,而不是
strs = '...' # This is a global variable
def testing(s):
... # Body of testing function that never references the local `s` variable
你应该有
def testing(strs):
... # Body of testing uses `strs` as before
没有理由对 ht.values()
进行排序,因此可以完全取消对 temp
的分配。
当您遍历 new_strs
时,您要做的就是创建一个包含 new_strs 中元素计数的列表。这是您存储在 ht
字典中的内容。所以
for s in new_strs:
final.append(ht[s])
现在 final 是一个列表,其中包含字符串在原始字符串中出现的次数的计数。您可以像现在一样返回。
我建议进行这些小改动并观察它是否有效。然后,一旦该功能按您的预期工作,就可以清理很多东西。
您可以使用 defaultdict 代替常规字典。您可以使用 list comprehension 来构建 final
列表。
from collections import defaultdict
def testing(strs):
ht = defaultdict(int)
new_strs = strs.split()
for s in new_strs:
ht[s] += 1 # if `s` is not in ht,the default 0 is used.
final = [strs(ht[s]) for s in new_strs]
return '|'.join(final)
字符串连接方法可以采用生成器,因此无需创建中间 final
变量。最后两行可以写成一行
return '|'.join(strs(ht[s]) for s in new_strs)
collections 模块有一个 Counter collection 可以准确地计算列表中的事物。你可以把这个函数写成:
from collections import Counter
def testing(strs):
new_strs = strs.split()
ht = Counter(new_strs)
return '|'.join(str(ht[s]) for s in new_strs)
,
这个问题自最初提出以来已经改变。所以这是一个新的答案。
def testing(strs):
new_strs = strs.split()
ht = Counter(new_strs)
ranks = rank(sorted(list(dict(ht).items()),key = lambda t: t[1],reverse=True))
ranks_dict = dict(ranks)
return '|'.join(str(ranks_dict[s]) for s in new_strs
你只需要 rank
函数,它接受一个 (value,score) 元组的排序列表并返回一个 (value,rank) 列表
def rank(tuples):
current_score = tuples[0][1]
current_rank = 1
ties = 0
ranks = []
for tup in tuples:
if tup[1] == current_score:
ties += 1
else:
current_rank = current_rank + ties
ties = 1
ranks.append((tup[0],current_rank))
current_score = tup[1]
return ranks
请注意,我正在计算出现次数相同且排名相同的两个词。在您的示例中,您将它们作为不同的等级,但没有提供确定哪个是哪个的方法。我希望这足以让您走上正轨。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。