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

标签 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+应该添加一个。

编辑:这是约束。


不要使用if语句
使用至少一个def,不包括main
没有进口

最佳答案

首先,您需要使用与costlist应该返回的数据“相似”的数据,将prices的每一项映射到其正确的直方图bin中。我之所以说“相似”,是因为例如对于a,它计算的是1 - 19,即1减去19,这是无用的-18,依此类推。

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

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


该列表列出了垃圾箱的下限列表(每个上限当然由下一个垃圾箱的下限给出)。因为您使用的是Python 3,所以我在list上调用range(在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(当然,应该始终在问题中始终明确明确地阐明此类约束!)显然是因为这是一个学校运动。

因此,如果您需要手动重新实现collections.Counter,则可以这样做...:

c = {}
for i in costlist:
    thebin = int2bin.get(i, lastbin)
    if thebin in c:
        c[thebin] += 1
    else:
        c[thebin] = 1


那里有-6条语句(将if / else计为1)而不是1(加上导入),并且对于这种特殊情况,我们重新实现了collections.Counter。就我个人而言,我认为使用适当的高级别抽象是最好和最明智的选择-尽管当然理解概念上的底层内容也很聪明。

但是计数的概念对于人类来说是很自然的(无论如何,从一年级开始,这种计数就已经渗透到学生中了),以至于我认为在这种情况下没有必要再重复一次!

“如果垃圾箱中已经有东西,而您又放了一个东西,则将其添加到垃圾箱中;如果垃圾箱中还没有东西,那么您将第一个想法放入垃圾箱中,然后启动垃圾箱。一口气” –真的值得让高中生再次参加这样的演习吗?

嗯,我没有受过老师的培训,所以我想我不会因为在学校的整个过程中如此无用地重复长时间被吸收的概念而感到非常无聊,而且我听到的完全相同我的孩子们回到学校时:-)。

回到有趣的东西...:

现在,在稍有不同的标题(您要说的那个标题)之后,仅保留打印任务:

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上堆积的最新限制:
-否,如果语句
-使用至少一个不包括main的def
-没有进口

defprices中已经存在,并且现在没有import(在非计数器版本中)。 “没有if语句”确实很荒谬(与在编码时必须只靠左脚站在一起!!),但是幸运的是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习惯用法,我提倡(甚至在我写“坚果中的Python”之前,我曾在上面敲过它:-)都是借用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]将引发一个IndexError,而except子句将处理该问题!

现在,如果我正确地评估了OP,我有两个预测:(A)这将是不够的(更多约束将源于虚无,例如“ no try / except语句”!-),以及(B)OP仍不可行接受此答案,然后打开所有约束的另一个问题。我怀疑自己是(A),因为我无法想象一个老师愿意接受try/except如果他们禁止简单得多的if;我只是希望我在(B)上写错了,也就是说,OP将意识到他们不会再花时间和精力,直到并且除非他们接受了这个问题,然后才无奈地单击该复选标记大纲再问一个... :-)

关于python - 在Python 3.4中更改直方图的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28180460/

相关文章:

python - 使用 matplotlib 和 seaborn 在多元时间序列图中突出显示时间间隔

检测循环最终迭代的 Pythonic 方法

python - 我应该将 Python 3.5 降级到 3.4 吗?

python - 使用Popen执行ffmpeg命令

python - unittest Mock - 补丁返回值

python - Python 不存在的行出错

Python with 语句,继续

python - 运行 python -m 的有限回溯

python - 中断事件循环后清理的正确方法是什么?

python - 推特 Bootstrap href 按钮不起作用