- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在研究 Python Challenge 中提出的问题.其中一个问题要求从一堆字符中筛选出最稀有的字符。
我的方法是从文本文件中读取字符,将字符/出现作为键/值对存储在字典中。按值对字典进行排序,并反转字典,其中出现是键,字符串是值。假设最稀有的字符只出现一次,我返回这个倒排字典的键等于 1 的值。
输入(funkymess.txt)是这样的:
%%$@$^_#)^)&!_+]!*@&^}@@%%+$&[(_@%+%$*^@ $^!+]!&#)*}{}}!]$[%}@[{@#_^{*......
代码如下:
from operator import itemgetter
characterDict = dict()
#put the characters in a dictionary
def putEncounteredCharactersInDictionary(lineStr):
for character in lineStr:
if character in characterDict:
characterDict[character] = characterDict[character]+1
else:
characterDict[character] = 1
#Sort the character dictionary
def sortCharacterDictionary(characterDict):
sortCharDict = dict()
sortsortedDictionaryItems = sorted(characterDict.iteritems(),key = itemgetter(1))
for key, value in sortsortedDictionaryItems:
sortCharDict[key] = value
return sortCharDict
#invert the sorted character dictionary
def inverseSortedCharacterDictionary(sortedCharDict):
inv_map = dict()
for k, v in sortedCharDict.iteritems():
inv_map[v] = inv_map.get(v, [])
inv_map[v].append(k)
return inv_map
f = open('/Users/Developer/funkymess.txt','r')
for line in f:
#print line
processline = line.rstrip('\n')
putEncounteredCharactersInDictionary(processline)
f.close()
sortedCharachterDictionary = sortCharacterDictionary(characterDict)
#print sortedCharachterDictionary
inversedSortedCharacterDictionary = inverseSortedCharacterDictionary(sortedCharachterDictionary)
print inversedSortedCharacterDictionary[1]r
有人可以看一下并为我提供一些指示,说明我在这里是否走在正确的轨道上,如果可能的话,从语言和算法的角度提供一些关于可能的优化/最佳实践和潜在重构的反馈.
谢谢
最佳答案
我想向您介绍重构的过程。学习编程不仅仅是了解最终结果,这是您在 Stack Overflow 上提问时通常得到的结果。这是关于如何自己得到那个答案。当人们针对此类问题发布简短而密集的答案时,并不总是很明显他们是如何得出解决方案的。
那么让我们进行一些重构,看看我们可以做些什么来简化您的代码。我们将重写、删除、重命名和重新排列代码,直到无法做出更多改进为止。
Python 不需要这么冗长。当您在 Python 中对列表和字典进行显式循环操作,而不是使用对整个容器进行操作的列表理解和函数时,通常会产生代码味道。
如果不存在,defaultdict(int)
将在访问时生成条目。这让我们在计算字符时消除 if/else 分支。
from collections import defaultdict
characterDict = defaultdict(int)
def putEncounteredCharactersInDictionary(lineStr):
for character in lineStr:
characterDict[character] += 1
字典不保证其键的任何顺序。您不能假定这些项目的存储顺序与您插入它们的顺序相同。因此,对 dict 条目进行排序,然后将它们放回另一个 dict 只会将它们重新打乱。
这意味着您的函数基本上是空操作。对项目进行排序后,您需要将它们保存为元组列表以保留它们的排序顺序。删除该代码后,我们可以将此方法缩减为一行。
def sortCharacterDictionary(characterDict):
return sorted(characterDict.iteritems(), key=itemgetter(1))
鉴于之前的评论,排序后您实际上不再有字典。但假设你这样做了,这个函数就是不鼓励显式循环的情况之一。在 Python 中,始终考虑如何一次对集合进行操作,而不是一次对一个项目进行操作。
def inverseSortedCharacterDictionary(sortedCharDict):
return dict((v, k) for k, v in sortedCharDict.iteritems())
在一行中,我们 (1) 遍历字典中的键/值对; (2) 切换它们并创建反转的值/键元组; (3) 从这些倒置的元组中创建一个字典。
您的方法名称很长且具有描述性。无需在评论中重复相同的信息。仅当您的代码不能 self 描述时才使用注释,例如当您有一个复杂的算法或一个不是很明显的不寻常结构时。
在命名方面,您的名字不必要地太长。我会坚持使用描述性远小于 的名称,并使它们更通用。不要使用 inverseSortedCharacterDictionary
,而是尝试使用 invertedDict
。这就是该方法所做的全部,它反转了一个字典。它是否传递了排序字符字典或任何其他类型的字典实际上并不重要。
根据经验,尽量使用最通用的名称,以便您的方法和变量尽可能通用。更通用意味着更可重用。
characters = defaultdict(int)
def countCharacters(string):
for ch in string:
characters[ch] += 1
def sortedCharacters(characters):
return sorted(characters.iteritems(), key=itemgetter(1))
def invertedDict(d):
return dict((v, k) for k, v in d.iteritems())
使用临时变量和辅助方法是一种很好的编程习惯,我赞赏您在程序中这样做。然而,现在我们已经足够简单,每行只有一两行,我们可能甚至不再需要它们。
这是按上述方式更改函数后的程序主体:
f = open('funkymess.txt', 'r')
for line in f:
countCharacters(line.rstrip('\n'))
f.close()
print sortedCharacters(characters)[0]
然后让我们继续并内联这些辅助方法,因为它们非常简单。这是所有重构后的最终程序:
#!/usr/bin/env python
from operator import itemgetter
from collections import defaultdict
characters = defaultdict(int)
f = open('funkymess.txt','r')
for line in f:
for ch in line.rstrip('\n'):
characters[ch] += 1
f.close()
print sorted(characters.iteritems(), key=itemgetter(1))[0]
关于Python Puzzle 代码审查(剧透),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4156699/
我正在开发一个名为 Quiz 的系统... 最后剩下的就是“线索”。目前我有 我想从 xml 中删除线索,因为很难
一旦拉取请求被批准,如果还有进一步的提交: 拉取请求应该转到 未获批准 自动状态。 这能做到吗? 最佳答案 能力推送新提交时取消过时的拉取请求批准 是 下的设置合并前需要拉取请求审查 在 branch
我想发送我的App进行外部Beta测试,所以我想为此使用Apple的新TestFlight系统。 我设法邀请了内部测试人员,他们可以测试该应用程序,因此我发现我必须将该应用程序提交给外部Beta测试。
对于以某种方式使这个 if 条件更短(更优雅),你有什么建议吗? if (@path.start_with? "scp" || @path.start_with? "http") @source
我管理一个在线目录。目前,内部人员手动更新,他们的更改立即可见。现在我们要添加一个验证步骤:Tom 进行更改,Jerry 批准。 我看到两条路,但都不优雅。 保留整个数据库的第二个“工作副本”。 在同
我的程序应该采用任意数量的单字文本字符串参数,每个参数的长度小于 128 个字符。它将所有文本从 stdin 复制到 stdout,但输入中看到的任何单词都会被单词 CENSORED 替换。到目前为止
我有一个团队在几个 GitHub 存储库中工作。每个存储库都有负责人(维护者)对拉取请求进行最终审查,如果可以则将其合并到 master 中。所有其他成员都是此存储库的开发人员和审阅者(但可能在另一个
是否有任何官方/有效的方式来发送对 Android 开发者指南的反馈?我注意到一个错误(一个页面建议使用文档中列为已弃用的方法)并且想知道是否有办法向网站上的工作人员指出它,但我找不到任何东西。 最佳
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
(来源:azureedge.net) 我的代码存储库位于 GitHub 中,我的管道在 Azure DevOps 中配置。 我需要让 Azure DevOps 检查和过滤提交到我的 GitHub 存储
我想编写一个函数,从列表中删除尾随的 nil。我首先尝试用递归优雅地写它,但结果是这样的: (defun strip-tail (lst) (let ((last-item-pos (positi
我在 git review 上得到以下内容: git review You are about to submit multiple commits. This is expected if you
我正在使用 Apple iTunes Connect 网站。我希望我的 iPhone friend 可以通过 testflight 安装我的应用程序。我的 friend 不属于我的工作团队,因此他没有
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我在 visual studio 2010 中使用 git 进行源代码控制。我可以使用诸如“git status”、“git commit”之类的命令,但是当我尝试使用“git review”时,我得
我是一名优秀的程序员,十分优秀!