我一直在研究一个读取文件文档中的行然后代码组织它们的代码。但是,我一度陷入困境,我的朋友告诉我我能用什么。代码有效,但似乎我不知道他在第7和第8行从底部做了什么。我使用####所以你们知道它是哪条线。
那么,基本上你怎么能重写那两行代码呢?为什么它们有效呢?我好像不懂字典 来自sys import argv
filename = input("Please enter the name of a file: ")
file_in=(open(filename, "r"))
print("Number of times each animal visited each station:")
print("Animal Id Station 1 Station 2")
animaldictionary = dict()
for line in file_in:
if '\n' == line[-1]:
line = line[:-1]
(a, b, c) = line.split(':')
ac = (a,c)
if ac not in animaldictionary:
animaldictionary[ac] = 0
animaldictionary[ac] += 1
alla = []
for key, value in animaldictionary:
if key not in alla:
alla.append(key)
print ("alla:",alla)
allc = []
for key, value in animaldictionary:
if value not in allc:
allc.append(value)
print("allc", allc)
for a in sorted(alla):
print('%9s'%a,end=' '*13)
for c in sorted(allc):
ac = (a,c)
valc = 0
if ac in animaldictionary:
valc = animaldictionary[ac]
print('%4d'%valc,end=' '*19)
print()
print("="*60)
print("Animals that visited both stations at least 3 times: ")
for a in sorted(alla):
x = 'false'
for c in sorted(allc):
ac = (a,c)
count = 0
if ac in animaldictionary:
count = animaldictionary[ac]
if count >= 3:
x = 'true'
if x is 'true':
print('%6s'%a, end=' ')
print("")
print("="*60)
print("Average of the number visits in each month for each station:")
#(alla, allc) =
#for s in zip(*animaldictionary.keys()):
# (alla,allc).append(s)
#print(alla, allc)
(alla,allc,) = (set(s) for s in zip(*animaldictionary.keys())) ##### how else can you write this
##### how else can you rewrite the next code
print('\n'.join(['\t'.join((c,str(sum(animaldictionary.get(ac,0) for a in alla for ac in ((a,c,),))//12)))for c in sorted(allc)]))
print("="*60)
print("Month with the maximum number of visits for each station:")
print("Station Month Number")
print("1")
print("2")
答案 0 :(得分:3)
你指出的两条线确实令人困惑。我会尽力解释它们,并建议其他实施方案。
第一个计算alla
和allc
的值:
(alla,allc,) = (set(s) for s in zip(*animaldictionary.keys()))
这几乎等同于您上面已经完成的用于构建alla
和allc
列表的循环。如果需要,您可以完全跳过它。但是,让我们解开它正在做的事情,这样你就可以真正理解它。
最里面的部分是animaldictionary.keys()
。这将返回一个包含字典中所有键的可迭代对象。由于animaldictionary
中的键是两值元组,因此您可以从迭代中获得。在大多数情况下,在处理字典时实际上没有必要调用keys
,因为对键视图的操作通常与在字典上直接执行相同操作相同。
继续前进,通过使用zip
调用zip(*keys)
函数来解锁密钥。这里发生了两件事。首先,*
语法将上面的iterable解包为单独的参数。因此,如果animaldictionary的密钥为("a1", "c1), ("a2", "c2"), ("a3", "c3")
,则会将这三个元组称为zip
作为单独的参数。现在,zip
所做的是将几个可迭代的参数转换为单个迭代,产生一个元组,每个元组的第一个值,然后是一个元组,每个元组的第二个值,依此类推。因此,zip(("a1", "c1"), ("a2", "c2"), ("a3", "c3"))
会返回一个生成("a1", "a2", "a3")
,后跟("c1", "c2", "c3")
。
下一部分是一个生成器表达式,它将zip
表达式中的每个值传递给set
构造函数。这有助于消除任何重复。 set
个实例在其他方面也很有用(例如找到交叉点),但这里不需要。
最后,将两组a
和c
值分配给变量alla
和allc
。他们用你的名字替换你已经拥有的名单(和相同的内容!)。
您已经有了替代方案,您可以将alla
和allc
计算为列表。使用集可能稍微有点效率,但对于少量数据可能并不重要。另一种更明确的方法是:
alla = set()
allc = set()
for key in animaldict: # note, iterating over a dict yields the keys!
a, c = key # unpack the tuple key
alla.add(a)
allc.add(c)
你问的第二行做了一些平均,并将结果组合成一个打印出来的巨大字符串。把这么多的东西塞进一行是非常糟糕的编程风格。事实上,它做了一些不必要的东西,这让它更加令人困惑。在这里,添加了几个换行符,使其全部适合屏幕。
print('\n'.join(['\t'.join((c,str(sum(animaldictionary.get(ac,0)
for a in alla for ac in ((a,c,),))//12)
)) for c in sorted(allc)]))
最里面的部分是for ac in ((a,c,),)
。这很愚蠢,因为它是一个单元组元组的循环。这是将元组(a,c)
重命名为ac
的一种方式,但它非常混乱且不必要。
如果我们将ac
的一次使用替换为明确写出的元组,则新的最内部部分为animaldictionary.get((a,c),0)
。这是一种编写animaldictionary[(a, c)]
的特殊方式,但如果KeyError
不在字典中,则不会产生导致(a, c)
的风险。相反,对于不存在的键,将返回默认值0
(传入get
)。
此get
来电已完成:(getcall for a in alla)
。这是一个生成器表达式,它从键中获取给定c
值的字典中的所有值
(如果该值不存在,则默认值为零。)
下一步是获取前一个生成器表达式中值的平均值:sum(genexp)//12
。这非常简单,但您应该注意,使用//
进行除法总是向下舍入到下一个整数。如果您想要更精确的浮点值,请仅使用/
。
下一部分是对'\t'.join
的调用,其参数是单个(c, avg)
元组。这是一个尴尬的结构,可以更清楚地写成c+"\t"+str(avg)
或"{}\t{}".format(c, avg)
。所有这些都会产生一个字符串,其中包含c
值,制表符和上面计算的平均字符串形式。
下一步是列表推导,[joinedstr for c in sorted(allc)]
(其中,joinstr是上一步中的join
调用)。在这里使用列表理解有点奇怪,因为不需要列表(生成器表达式也可以这样做)。
最后,列表理解与换行符结合并打印:print("\n".join(listcomp))
。这很简单。
无论如何,通过使用一些变量并在循环中分别打印每一行,可以更清晰地重写整个混乱:
for c in sorted(allc):
total_values = sum(animaldictionary.get((a,c),0) for a in alla)
average = total_values // 12
print("{}\t{}".format(c, average))
要完成,我有一些一般的建议。
首先,您的数据结构可能不适合您对数据的使用。不是让animaldict
成为具有(a,c)
个键的字典,而是拥有嵌套结构可能更有意义,您可以在其中单独索引每个级别。也就是animaldict[a][c]
。使第二个字典包含以相反顺序索引的相同值甚至是有意义的(例如,一个被索引[a][c]
而另一个被索引[c][a]
)。使用这种方法,您可能不需要alla
和allc
列表进行迭代(您只需直接遍历主词典的内容)。
我的第二个建议是代码风格。您的许多变量名称都很差,要么是因为他们的名字没有任何意义(例如c
),要么名称暗示意义不正确。最明显的问题是您的key
和value
变量,实际上解包了两个密钥(AKA a
和c
)。在其他情况下,您可以将键和值组合在一起,但只有当您在字典的items()
视图上而不是直接在字典上进行迭代时才会获得。