【问题标题】:Rounding to specific numbers in Python 3.6在 Python 3.6 中舍入到特定数字
【发布时间】:2017-04-13 17:35:21
【问题描述】:

我正在尝试制作一个潜水表,其中的一些数字不是我可以看到的模式,因此我必须手动添加所有值,但我需要获取输入并将其四舍五入到最接近的值字典中的数字。

我需要将输入转换回字符串以确保输出正确:

代码:

class DepthTable:

    def __init__(self):
        self.d35 = {"10": "A",
                    "19": "B",
                    "25": "C",
                    "29": "D",
                    "32": "E",
                    "36": "F",
                   }



    def getpressureGroup(self, depth, time):

        if depth == "35":
            output = self.d35[time]
        else:
            output = "No info for that depth"
        print(output)


if __name__ == "__main__":
    depthtable = DepthTable()
    print("Please enter Depth (Use numbers!)")
    depth = input()
    print("Please Enter time!")
    time = input()
    depthtable.getpressureGroup(depth,time)

因此,当“玩家”输入数字 15 时,我需要将其向上舍入到 19(即使是 13 或类似的值也始终向上。)我不知道如何使用 round( ) 或者我可能必须创建一个检查每个数字的函数..

【问题讨论】:

  • 为什么不在 if 循环下和变量输出下,使用 if 来检查数字是否大于某个数字且小于某个其他数字,因此 15 的情况将大于 10 或如果满足这些条件,则小于 19 将时间更改为等于 19?这有意义吗?
  • 好吧,我的意思是这样的东西会成为一个大代码,实际的潜水表有 A-Z,每个都有 20 个时间戳..
  • 所以问题是您需要将每个数字推到至少与该数字一样大的最小值?
  • 我不太了解你,但我基本上需要有保障,因为它是潜水你想要安全所以我们将数字四舍五入而不是像11这样的通常数学中的向下最多 19 不是 10,而是 9 到 10。
  • 使用 pandas 中的cut 怎么样:import pandas as pd 然后:pd.cut([time], bins = np.array([0,10,19,25,29,32, np.inf]), labels = np.array(['A','B','C','D','E','F']), right = True)

标签: python python-3.6


【解决方案1】:

使用您的“检查每个数字的函数”的想法,实例变量keys 可用于获取密钥(如果存在)或下一个最高密钥:

class DepthTable:

    def __init__(self):
        self.d35 = {10: "A",
                    19: "B",
                    25: "C",
                    29: "D",
                    32: "E",
                    36: "F",
                   }

        self.keys = self.d35.keys()


    def getpressureGroup(self, depth, time):
        if depth == 35:
            rtime = min([x for x in self.keys if x >= time]) # if exists get key, else get next largest
            output = self.d35[rtime]
        else:
            output = "No info for that depth"
        print(output)


if __name__ == "__main__":
    depthtable = DepthTable()
    print("Please enter Depth (Use numbers!)")
    depth = int(input())
    print("Please Enter time!")
    time = int(input())
    depthtable.getpressureGroup(depth,time)

演示:

Please enter Depth (Use numbers!)
35
Please Enter time!
13
B

Please enter Depth (Use numbers!)
35
Please Enter time!
19
B

Please enter Depth (Use numbers!)
35
Please Enter time!
10
A

【讨论】:

  • 不错。而且由于您没有在其他任何地方使用self.keys,您实际上可以跳过为它保留一个变量,并直接在理解中使用self.d35.keys()。说到这一点,您也可以取消理解,而只使用“裸”生成器表达式。无论如何,那些只是尼特。这是对 OP 问题的快速和直接的解决方案。
  • 很好的观察@JohnY,感谢您的反馈
【解决方案2】:

d35 字典转换为排序列表并单步执行:

In [4]: d35 = {"10": "A",
   ...:                     "19": "B",
   ...:                     "25": "C",
   ...:                     "29": "D",
   ...:                     "32": "E",
   ...:                     "36": "F",
   ...:                    }

In [5]: sorted(d35.items())
Out[5]: [('10', 'A'), ('19', 'B'), ('25', 'C'), ('29', 'D'), ('32', 'E'), ('36', 'F')]

In [7]: time = 15

In [11]: for max_time, group_name in sorted(d35.items()):
    ...:     if int(max_time) >= time:
    ...:         break
    ...:

In [12]: max_time
Out[12]: '19'

In [13]: group_name
Out[13]: 'B'

修改你的方法可以做到这一点。我在 for 循环中添加了一个 else 来处理任何组未涵盖的时间。

def getpressureGroup(self, depth, time):

    if depth == "35":
        for max_time, group_name in sorted(self.d35.items()):
            if int(max_time) >= time:
                output = group_name
                break
        else:
            output = "No info for that depth"
    else:
        output = "No info for that depth"
    print(output)

【讨论】:

  • 你能不能把这个放到一个.py文件中我不太会看代码,这样对我来说会更容易
【解决方案3】:

您可以尝试使用pandas 模块中的cut

或多或少,它是将连续变量分成离散的类别,如压力组的深度。

您需要指定一个 bin 数组来将数据剪切到其中,然后您可以对其进行标记。

所以,举个例子:

import pandas as pd
import numpy as np

timestocut = [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]
pd.cut(timestocut, bins = np.array([-1,10,19,25,29,32, np.inf]), labels = np.array(['A','B','C','D','E','F']), right = True)

给予:

[A, A, A, B, B, C, C, D, E, F]
Categories (6, object): [A < B < C < D < E < F]

您可以看到 bin 的值为 -1,因此我们包含 0 和 np.inf 以捕获无限大的任何内容。

将其集成到您的代码中取决于您 - 我个人会删除 dict 并使用此映射。

【讨论】:

  • 对不起,但我还是不太明白...我是 python 新手,不知道不运行代码的作用。
  • 所以现在看一下,函数 pd.cut 已经将timestocut ([0, 4, 8, 12, 16, 20, 24, 28, 32, 36]) 转换为输出 ([A, A, A, B, B, C, C, D, E, F]),方法是根据给定的 bin 对它们进行 binning,并标记每个 bin使用给定的标签。
  • 那么np.array([-1,10,19,25,29,32, np.inf]) 是做什么的?
  • 这是一个 numpy 数组,它为我们提供了 bin。所以,-1 到 10 之间的任何东西都在 bin1 中,10 到 19 之间的东西在 bin2 中等等。然后使用包含名称的下一个数组标记这些 bin。
  • 好的,我想我知道了,我会试试看。编辑:在np.arrays 中找不到arrays 我只是傻吗?
【解决方案4】:

对于大型列表,请使用标准 bisect 模块或任何其他二分法包。 查看友好的 python 文档,了解如何使用 bisect 解决您的任务的详细说明

https://docs.python.org/2/library/bisect.html#other-examples

如果你有 numpy,试试 digitize,好像比 pandas cut 容易

Python: Checking to which bin a value belongs

但是对于这么短的列表,我只会使用简单的分支

if 1<x<=18:
    ...
elif 18<x<=28:
    ...
elif

或者,为了更快地构建案例数组或字典 { "1":"19", "2":"19" ... "20": "25" ...} 以编程方式,

用一个activestate字典反转sn-p说

http://code.activestate.com/recipes/415100-invert-a-dictionary-where-values-are-lists-one-lin/

def invert(d):
   return dict( (v,k) for k in d for v in d[k] ) 

d35 = {"10": "A",
                    "19": "B",
                    "25": "C",
                    "29": "D",
                    "32": "E",
                    "36": "F",
                   }

dlist = d35.keys().sort()
d1 = {}
low = -1
for n in dlist[1:]:
    up = int(n) + 1

    interval = range(low, up)
    low = up
    d1[ dlist[i] ] = map(str, interval)


 result = invert(d1)

【讨论】:

  • 哎呀!我仍然会保持这个答案开放,看看是否有人有比暴力破解更好的答案,但机会似乎不太大。
  • 我的意思是您正在检查数字存在的范围,这就是我所看到的逻辑。如果不检查 x1 和 x2,我看不出你还能怎么做
  • 我明白了,似乎有像@jermycg 所说的那样的某种库
【解决方案5】:

虽然 bisectpandas.cut (如其他答案中所述)可以工作,但您可以通过循环遍历截止值来仅使用普通 Python(无导入模块)来实现。 (这是@Harvey's answer 中的方法,只是以程序而不是交互式会话的形式呈现。)

d35 = {
    10: "A",
    19: "B",
    25: "C",
    29: "D",
    32: "E",
    36: "F",
}

def pressure_group(time):
    for cutoff in sorted(d35.items()):
        if cutoff[0] >= time:
            return cutoff[1]
    return None  # or pick something else for "too high!"

这比使用提到的模块要冗长一些,但可能更容易理解和理解发生了什么,因为你自己做这一切(我认为这通常是一个好主意,特别是如果你试图学习编程)。

每次循环,cutoff 都是来自d35 字典的一对。由于这些对是从最低到最高排序的,因此您可以在大于或等于输入的第一个处停止。如果循环结束(因为输入高于最高截止值),我选择返回 None,但您可以返回其他值,或引发异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 1970-01-01
    • 2020-06-18
    相关资源
    最近更新 更多