在Python 3.4中更改直方图的范围

时间:2015-01-27 21:35:17

标签: python 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-910-19,最后一个范围100+应添加一个。{/ p>

编辑:这是限制因素。

  • 不要使用if语句
  • 至少使用一个def不包括main
  • 没有导入

1 个答案:

答案 0 :(得分:1)

您首先需要将costlist的每个项目映射到其正确的直方图区域,使用数据&#34;类似&#34; prices应该返回的内容。我说&#34;类似&#34;因为例如a它计算1 - 19,一个减去十九,这是一个无用的-18,等等。

首先,更改prices以返回有用的而不是那些无用的差异,例如:

def prices():
    return [1] + list(range(20, 110, 10))

列出了bin的下界列表(每个上界当然由下一个bin的下界给出)。我在list上呼叫range,因为您正在使用Python 3(在Python 2中您可以忽略`列表)。

使用这些数据的最简单方法是构建一个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是不受欢迎的(当然,这些约束应该首先在问题中清楚明确地阐明!)显然是因为这是一次学校运动。

所以,如果您需要手动重新实施collections.Counter,当然可以这样做......:

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。就个人而言,我认为使用适当的高级抽象是最好和最明智的 - 尽管当然,理解它们在概念上的位置也很明智。

但是计数的概念对于人类来说是如此自然(并且无论如何从一年级开始就已经钻进了学生),我认为这不是必要的在这种情况下再次重复它!

&#34;如果垃圾箱里已有东西,你又放了一个,然后在垃圾箱里加一个;如果垃圾箱里还没有任何东西,那么你要把第一个想法放在垃圾箱里,然后在一个垃圾箱里开始垃圾箱的计数。 - 要求高年级学生再次参加再次真的值得吗?

好吧,我没有接受过老师的培训,所以我想我不会因为长时间吸收的概念完全如此无用的重复而咆哮我是多么的无聊 整个我的在学校的时间 - 当我的孩子们他们在学校时,我听到了同样的答案: - )。

回到真正有趣的东西......:

现在,只有一个略有不同的标题(你想说的那个)之后,只有打印任务仍然存在:

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在这个Q上堆积的最新额外限制: - 不,如果声明 - 使用至少一个def不包括main - 没有进口

def已经存在prices,现在没有import(在非计数器版本中)。 &#34;没有if陈述&#34;真的很荒谬(与编码时必须站在左脚一样! - )幸运的是,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,我们假设它已经,并处理它没有产生的例外。这实际上是一个公认的Python成语,我提出了这个问题(甚至在我写完&#34; Python在一个坚果壳中#34;在那里我抨击它:-) as&#34;它更容易请求宽恕而不是许可&#34;,借用Commodore Hopper的伟大座右铭(请参阅https://www.youtube.com/watch?v=AZDWveIdqjY我的主题演讲)。

我们将使用完全相同的技巧删除其他 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]会提升一个IndexErrorexcept子句处理它!

现在,如果我正确地评估OP,我有两个预测:(A)这是不够的(更多的约束将从虚无中产生,例如&#34;没有尝试/除语句&#34;! - )和(B)OP 不接受此答案,并使用所有约束打开另一个问题。我怀疑我是现场重拍(A)因为如果他们禁止更简单的try/except,我无法想象一位愿意接受if的老师;我可以希望我(B)错了,即OP会意识到他们不会再获得一点时间和精力,除非他们接受这个问题,从而不情愿地点击在那个复选标记大纲上,问另一个......: - )