Python拼图代码评论(剧透)

我一直致力于解决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中使用列表和dicts操作显式循环时,通常会出现代码异味,而不是使用对容器作为整体进行操作的列表推导和函数.

使用defaultdict存储字符计数

defaultdict(int)将在访问它们时生成条目(如果它们不存在).这让我们在计算字符时消除if / else分支.

from collections import defaultdict
characterDict = defaultdict(int)

def putEncounteredCharactersInDictionary(lineStr):
    for character in lineStr:
        characterDict[character] += 1

排序dicts

字典不保证其密钥的任何排序.您不能假设这些项目的存储顺序与您插入它们的顺序相同.因此,对dict条目进行排序,然后将它们放回到另一个dict中,只需将它们重新加入即可.

这意味着你的功能基本上是一个无操作.对项目进行排序后,您需要将它们保留为元组列表以保留其排序顺序.删除该代码后,我们可以将此方法减少到一行.

def sortCharacterDictionary(characterDict):
    return sorted(characterDict.iteritems(), key=itemgetter(1))

反转词

鉴于之前的评论,您在排序后将不再拥有dict.但假设您这样做,此函数是不鼓励显式循环的情况之一.在Python中,始终考虑如何一次操作集合而不是一次操作一个项目.

def inverseSortedCharacterDictionary(sortedCharDict):
    return dict((v, k) for k, v in sortedCharDict.iteritems())

在一行中,我们(1)迭代dict中的键/值对; (2)切换它们并创建反转值/键元组; (3)用这些倒置的元组创建一个字典.

明智地评论和命名

您的方法名称很长且具有描述性.没有必要在评论中重复相同的信息.仅在代码不具有自我描述性时才使用注释,例如,当您有复杂的算法或不明显的异常构造时.

在命名方面,你的名字不必要很长.我会坚持使用更少描述性的名称,并使它们更通用.而不是inverseSortedCharacterDictionary,尝试只是invertDict.这就是所有方法所做的,它颠倒了一个字典.如果它传递了排序的字符字典或任何其他类型的字典,那实际上并不重要.

根据经验,尝试使用最通用的名称,以便您的方法和变量尽可能通用.更通用意味着更可重用.

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拼图代码评论(剧透) - 代码日志