在 Python 3.4 中更改直方图的范围
Changing the range of the histogram in Python 3.4
这是一个显示下面列表的直方图的程序:
costlist = [48, 43, 51, 36, 6, 25, 51, 71,
59, 70, 78, 36, 18, 84, 5, 9, 13,
90, 71, 39, 80, 2, 69, 48, 21,
66, 10, 37, 89, 20, 27, 7, 12,
314, 83, 39, 31, 36, 56, 60,
62, 23, 70, 51, 46, 40, 100,
29, 30, 59, 37, 94, 99, 20, 88,
10, 36, 42, 14, 24, 33, 60, 370,
2, 30, 32, 85, 14, 52, 47, 16,
25, 21, 29, 78, 83, 310, 43, 62,
54, 83, 74, 52, 65, 82, 44, 94,
83, 21, 36, 41, 67, 81, 32, 28,
87, 62, 12]
结果是:
Element Value Histogram
0-9 6
10-19 9
20-29 13
30-39 15
40-49 10
50-59 9
60-69 9
70-79 7
80-89 12
90-99 4
但是,我希望它输出每个范围内的项目数:
Range Value Histogram
1 - 19 4 ****
20 - 29 5 *****
30 - 39 0
40 - 49 0
50 - 59 0
60 - 69 5 *****
70 - 79 10 **********
80 - 89 0
90 - 99 0
100+ 3 ***
这是我的代码:
def production_cost():
costlist = [48, 43, 51, 36, 6, 25, 51, 71,
59, 70, 78, 36, 18, 84, 5, 9, 13,
90, 71, 39, 80, 2, 69, 48, 21,
66, 10, 37, 89, 20, 27, 7, 12,
314, 83, 39, 31, 36, 56, 60,
62, 23, 70, 51, 46, 40, 100,
29, 30, 59, 37, 94, 99, 20, 88,
10, 36, 42, 14, 24, 33, 60, 370,
2, 30, 32, 85, 14, 52, 47, 16,
25, 21, 29, 78, 83, 310, 43, 62,
54, 83, 74, 52, 65, 82, 44, 94,
83, 21, 36, 41, 67, 81, 32, 28,
87, 62, 12]
return costlist
def count_scores(scores, low, high):
if
return len([x for x in scores if x >= low and x <= high])
def histogram(costlist):
d = {'%d-%d'%(x, x + 9):
count_scores(costlist, x, x + 9) for x in range(0, 100, 10)}
for k,v in sorted(d.items()):
print ('%7s %5d'%(k,v))
def main():
costlist = production_cost()
print("%7s %5s %10s" %("Element", "Value", "Histogram"))
histogram(costlist)
main()
我的代码运行正确,除了它没有星号并且范围丢失了一些东西。 0-9
和 10-19
应该合并,最后一个范围 100+
.
应该加一个
编辑:这是限制条件。
- 不要使用 if 语句
- 使用至少一个 def 不包括 main
- 没有导入
您首先需要将 costlist
的每个项目映射到其正确的直方图容器中,使用数据 "similar" 到 prices
应该 return 的数据。我说 "similar" 因为例如 a
它计算 1 - 19
,一减十九,这是无用的 -18
,等等。
所以,首先,将 prices
更改为 return 一些 有用的 而不是那些无用的差异,例如:
def prices():
return [1] + list(range(20, 110, 10))
列出 bin 的下限列表(每个上限当然由下一个 bin 的下限给出)。我在 range
上调用 list
,因为您使用的是 Python 3(在 Python 2 中,您可以省略 `list)。
使用这些数据的最简单方法是构建一个 dict
将范围内的每个整数映射到它的 bin 编号(这样寻找给定整数的 bin 几乎是即时的,而不是花一些时间其他表述):
p = prices()
int2bin = {}
for i in range(1, len(p)):
for j in range(p[i-1], p[i]):
int2bin[j] = i - 1
lastbin = len(p) - 1
现在为每个整数找到 bin 是微不足道的,因此,计算每个给定 bin 中有多少整数同样微不足道:
import collections
c = collections.Counter(
int2bin.get(i, lastbin)
for i in costlist)
补充:OP 刚刚评论(虽然 Q 没有相应编辑)模块 collections
是不受欢迎的(当然,首先应该在问题中清楚明确地说明这些限制!) 显然是因为这是学校练习。
因此,如果您需要手动 re-implement collections.Counter
,您当然可以这样做...:[=51=]
c = {}
for i in costlist:
thebin = int2bin.get(i, lastbin)
if thebin in c:
c[thebin] += 1
else:
c[thebin] = 1
有 -- 六个语句(将 if/else 算作一个)而不是一个(加上导入),我们为这种特殊情况重新实现了 collections.Counter
。我个人认为使用适当的高层次抽象是最好和最明智的——当然从概念上理解它们下面的内容也是明智的。
但是 计数 的概念对人类来说是如此自然(无论如何从一年级开始就被灌输给学生),我认为没有必要在这种情况下再重复一遍!
"If there are already things in the bin and you put another one there, then add one to the bin's count; if there were no things in the bin yet, so you're putting the first think in the bin, then start the bin's count at one" -- 让高中生再次真的值得吗?!
啊好吧,我没有受过教师培训,所以我想我不会抱怨 无聊 我是多么无用地重复 [=134] =] 在我 我 上学期间的概念——当 他们 在学校时,我从 children 那里听到完全相同的内容: -).
返回 actually-fun 内容...:
现在,只剩下打印任务了,经过一个稍微不同的header(你说你想要的那个):
print("%7s %5s %10s" %("Range", "Value", "Histogram"))
您可以循环遍历垃圾箱:
for i, lo in enumerate(p):
if i + 1 < len(p):
rng = '%d-%d' % (lo, p[i+1]-1)
else:
rng = '%d+' % lo
val = c[i]
stars = '*' * val
print("%7s %5s %-10s" %(rng, val, stars))
把它们放在一起,你会看到结果:
Range Value Histogram
1-19 15 ***************
20-29 13 *************
30-39 15 ***************
40-49 10 **********
50-59 9 *********
60-69 9 *********
70-79 7 *******
80-89 12 ************
90-99 4 ****
100+ 4 ****
这似乎是您要的。
当然还有其他选择(例如,使用 dict
以外的其他方法来完成从整数到 bin 编号的映射)和可能需要解释的事情,具体取决于您的 Python 技能,所以, 欢迎进一步提问!
已添加:以下是 OP 在此问题上积累的最新额外限制:
- 没有 if 语句
- 使用至少一个 def 不包括 main
- 没有进口
def
已经存在于 prices
中,现在没有 import
(在 non-Counter 版本中)。 "No if
statements" 真的很荒谬(相当于在编码时必须只用左脚站立!-)但幸运的是 Python 提供了解决这些荒谬的技巧。
所以要构建计数器,让我们使用:
def counter(costlist):
c = {}
for i in costlist:
thebin = int2bin.get(i, lastbin)
try:
c[thebin] += 1
except KeyError:
c[thebin] = 1
这是第一个 if
删除技巧:而不是更自发地检查 thebin
是否已经被放入 dict
c
,这里我们假设它有,并处理它没有时产生的异常。这实际上是一个 well-recognized Python 成语,我提倡它(甚至在我写 "Python in a Nutshell" 之前,我在那里猛烈抨击它:-) 作为 "It's easier to ask forgiveness than permission",借用 Commodore Hopper 的伟大格言(请参阅 https://www.youtube.com/watch?v=AZDWveIdqjY 我关于该主题的演讲)。
我们将使用 完全 相同的技巧来删除 other if
,只需改写该片段:
for i, lo in enumerate(p):
if i + 1 < len(p):
rng = '%d-%d' % (lo, p[i+1]-1)
else:
rng = '%d+' % lo
与:
for i, lo in enumerate(p):
try:
rng = '%d-%d' % (lo, p[i+1]-1)
except IndexError:
rng = '%d+' % lo
在这里,它起作用是因为,如果 (i + 1)
不是 而不是 < len(p)
,正如最初由正常 if
检查的那样,索引 p[i+1]
将引发 IndexError
,而 except
子句处理该问题!
现在,如果我正确地评估了 OP,我有两个预测:(A) 这还不够(更多的约束将 spring 来自虚无,例如 "no try/except statements"!-) 和 ( B) OP 将 still 不接受这个答案并用 all 约束打开另一个问题。我怀疑我是 spot-on re (A) 因为我无法想象一个老师愿意接受 try/except
如果他们禁止 much-simpler if
;我只能希望我在 (B) 上错了,即 OP 会意识到他们不会再从我这里得到一点时间和精力,除非他们接受这个问题,从而不情愿地点击那个复选标记大纲并问另一个...:-)
这是一个显示下面列表的直方图的程序:
costlist = [48, 43, 51, 36, 6, 25, 51, 71,
59, 70, 78, 36, 18, 84, 5, 9, 13,
90, 71, 39, 80, 2, 69, 48, 21,
66, 10, 37, 89, 20, 27, 7, 12,
314, 83, 39, 31, 36, 56, 60,
62, 23, 70, 51, 46, 40, 100,
29, 30, 59, 37, 94, 99, 20, 88,
10, 36, 42, 14, 24, 33, 60, 370,
2, 30, 32, 85, 14, 52, 47, 16,
25, 21, 29, 78, 83, 310, 43, 62,
54, 83, 74, 52, 65, 82, 44, 94,
83, 21, 36, 41, 67, 81, 32, 28,
87, 62, 12]
结果是:
Element Value Histogram
0-9 6
10-19 9
20-29 13
30-39 15
40-49 10
50-59 9
60-69 9
70-79 7
80-89 12
90-99 4
但是,我希望它输出每个范围内的项目数:
Range Value Histogram
1 - 19 4 ****
20 - 29 5 *****
30 - 39 0
40 - 49 0
50 - 59 0
60 - 69 5 *****
70 - 79 10 **********
80 - 89 0
90 - 99 0
100+ 3 ***
这是我的代码:
def production_cost():
costlist = [48, 43, 51, 36, 6, 25, 51, 71,
59, 70, 78, 36, 18, 84, 5, 9, 13,
90, 71, 39, 80, 2, 69, 48, 21,
66, 10, 37, 89, 20, 27, 7, 12,
314, 83, 39, 31, 36, 56, 60,
62, 23, 70, 51, 46, 40, 100,
29, 30, 59, 37, 94, 99, 20, 88,
10, 36, 42, 14, 24, 33, 60, 370,
2, 30, 32, 85, 14, 52, 47, 16,
25, 21, 29, 78, 83, 310, 43, 62,
54, 83, 74, 52, 65, 82, 44, 94,
83, 21, 36, 41, 67, 81, 32, 28,
87, 62, 12]
return costlist
def count_scores(scores, low, high):
if
return len([x for x in scores if x >= low and x <= high])
def histogram(costlist):
d = {'%d-%d'%(x, x + 9):
count_scores(costlist, x, x + 9) for x in range(0, 100, 10)}
for k,v in sorted(d.items()):
print ('%7s %5d'%(k,v))
def main():
costlist = production_cost()
print("%7s %5s %10s" %("Element", "Value", "Histogram"))
histogram(costlist)
main()
我的代码运行正确,除了它没有星号并且范围丢失了一些东西。 0-9
和 10-19
应该合并,最后一个范围 100+
.
编辑:这是限制条件。
- 不要使用 if 语句
- 使用至少一个 def 不包括 main
- 没有导入
您首先需要将 costlist
的每个项目映射到其正确的直方图容器中,使用数据 "similar" 到 prices
应该 return 的数据。我说 "similar" 因为例如 a
它计算 1 - 19
,一减十九,这是无用的 -18
,等等。
所以,首先,将 prices
更改为 return 一些 有用的 而不是那些无用的差异,例如:
def prices():
return [1] + list(range(20, 110, 10))
列出 bin 的下限列表(每个上限当然由下一个 bin 的下限给出)。我在 range
上调用 list
,因为您使用的是 Python 3(在 Python 2 中,您可以省略 `list)。
使用这些数据的最简单方法是构建一个 dict
将范围内的每个整数映射到它的 bin 编号(这样寻找给定整数的 bin 几乎是即时的,而不是花一些时间其他表述):
p = prices()
int2bin = {}
for i in range(1, len(p)):
for j in range(p[i-1], p[i]):
int2bin[j] = i - 1
lastbin = len(p) - 1
现在为每个整数找到 bin 是微不足道的,因此,计算每个给定 bin 中有多少整数同样微不足道:
import collections
c = collections.Counter(
int2bin.get(i, lastbin)
for i in costlist)
补充:OP 刚刚评论(虽然 Q 没有相应编辑)模块 collections
是不受欢迎的(当然,首先应该在问题中清楚明确地说明这些限制!) 显然是因为这是学校练习。
因此,如果您需要手动 re-implement collections.Counter
,您当然可以这样做...:[=51=]
c = {}
for i in costlist:
thebin = int2bin.get(i, lastbin)
if thebin in c:
c[thebin] += 1
else:
c[thebin] = 1
有 -- 六个语句(将 if/else 算作一个)而不是一个(加上导入),我们为这种特殊情况重新实现了 collections.Counter
。我个人认为使用适当的高层次抽象是最好和最明智的——当然从概念上理解它们下面的内容也是明智的。
但是 计数 的概念对人类来说是如此自然(无论如何从一年级开始就被灌输给学生),我认为没有必要在这种情况下再重复一遍!
"If there are already things in the bin and you put another one there, then add one to the bin's count; if there were no things in the bin yet, so you're putting the first think in the bin, then start the bin's count at one" -- 让高中生再次真的值得吗?!
啊好吧,我没有受过教师培训,所以我想我不会抱怨 无聊 我是多么无用地重复 [=134] =] 在我 我 上学期间的概念——当 他们 在学校时,我从 children 那里听到完全相同的内容: -).
返回 actually-fun 内容...:
现在,只剩下打印任务了,经过一个稍微不同的header(你说你想要的那个):
print("%7s %5s %10s" %("Range", "Value", "Histogram"))
您可以循环遍历垃圾箱:
for i, lo in enumerate(p):
if i + 1 < len(p):
rng = '%d-%d' % (lo, p[i+1]-1)
else:
rng = '%d+' % lo
val = c[i]
stars = '*' * val
print("%7s %5s %-10s" %(rng, val, stars))
把它们放在一起,你会看到结果:
Range Value Histogram
1-19 15 ***************
20-29 13 *************
30-39 15 ***************
40-49 10 **********
50-59 9 *********
60-69 9 *********
70-79 7 *******
80-89 12 ************
90-99 4 ****
100+ 4 ****
这似乎是您要的。
当然还有其他选择(例如,使用 dict
以外的其他方法来完成从整数到 bin 编号的映射)和可能需要解释的事情,具体取决于您的 Python 技能,所以, 欢迎进一步提问!
已添加:以下是 OP 在此问题上积累的最新额外限制: - 没有 if 语句 - 使用至少一个 def 不包括 main - 没有进口
def
已经存在于 prices
中,现在没有 import
(在 non-Counter 版本中)。 "No if
statements" 真的很荒谬(相当于在编码时必须只用左脚站立!-)但幸运的是 Python 提供了解决这些荒谬的技巧。
所以要构建计数器,让我们使用:
def counter(costlist):
c = {}
for i in costlist:
thebin = int2bin.get(i, lastbin)
try:
c[thebin] += 1
except KeyError:
c[thebin] = 1
这是第一个 if
删除技巧:而不是更自发地检查 thebin
是否已经被放入 dict
c
,这里我们假设它有,并处理它没有时产生的异常。这实际上是一个 well-recognized Python 成语,我提倡它(甚至在我写 "Python in a Nutshell" 之前,我在那里猛烈抨击它:-) 作为 "It's easier to ask forgiveness than permission",借用 Commodore Hopper 的伟大格言(请参阅 https://www.youtube.com/watch?v=AZDWveIdqjY 我关于该主题的演讲)。
我们将使用 完全 相同的技巧来删除 other if
,只需改写该片段:
for i, lo in enumerate(p):
if i + 1 < len(p):
rng = '%d-%d' % (lo, p[i+1]-1)
else:
rng = '%d+' % lo
与:
for i, lo in enumerate(p):
try:
rng = '%d-%d' % (lo, p[i+1]-1)
except IndexError:
rng = '%d+' % lo
在这里,它起作用是因为,如果 (i + 1)
不是 而不是 < len(p)
,正如最初由正常 if
检查的那样,索引 p[i+1]
将引发 IndexError
,而 except
子句处理该问题!
现在,如果我正确地评估了 OP,我有两个预测:(A) 这还不够(更多的约束将 spring 来自虚无,例如 "no try/except statements"!-) 和 ( B) OP 将 still 不接受这个答案并用 all 约束打开另一个问题。我怀疑我是 spot-on re (A) 因为我无法想象一个老师愿意接受 try/except
如果他们禁止 much-simpler if
;我只能希望我在 (B) 上错了,即 OP 会意识到他们不会再从我这里得到一点时间和精力,除非他们接受这个问题,从而不情愿地点击那个复选标记大纲并问另一个...:-)