在 Python 中的元组值列表中查找某个范围内的值

发布于 2024-09-25 08:56:54 字数 876 浏览 2 评论 0原文

我正在尝试获取标准 BMI 范围内的 BMI 值的身体质量指数 (BMI) 分类 - 例如,如果某人的 BMI 为 26.2,则他们将处于“超重”范围内。

我制作了一个值元组列表(见下文),尽管我当然对任何其他数据结构持开放态度。使用 SQL 的 BETWEEN 可以很容易地做到这一点,但我想用纯 Python 来实现,主要是因为这意味着更少的数据库连接,而且也是在“纯”Python 中做更多事情的练习。

bmi_ranges = []
bmi_ranges.append((u'Underweight', u'Severe Thinness', 0, 15.99))
bmi_ranges.append((u'Underweight', u'Moderate Thinness', 16.00, 16.99))
bmi_ranges.append((u'Underweight', u'Mild Thinness', 17.00, 18.49))
bmi_ranges.append((u'Normal Range', u'Normal Range', 18.50, 24.99))
bmi_ranges.append((u'Overweight', u'Overweight', 25.00, 29.99))
bmi_ranges.append((u'Obese', u'Obese Class I', 30.00, 34.99))
bmi_ranges.append((u'Obese', u'Obese Class II', 35.00, 39.99))
bmi_ranges.append((u'Obese', u'Obese Class III', 40.00, 1000.00))

如果元组列表中的范围完全,那么只需使用 listcomp 进行迭代就很容易了,但是如何找到某个值在任何其他值的范围内呢?

I'm trying to get the Body Mass Index (BMI) classification for a BMI value that falls within a standard BMI range - for instance, if someone's BMI were 26.2, they'd be in the "Overweight" range.

I made a list of tuples of the values (see below), although of course I'm open to any other data structure. This would be easy to do with SQL's BETWEEN but I'd like to do it in pure Python, mostly because it means one fewer DB connections but also as an exercise in doing more in "pure" Python.

bmi_ranges = []
bmi_ranges.append((u'Underweight', u'Severe Thinness', 0, 15.99))
bmi_ranges.append((u'Underweight', u'Moderate Thinness', 16.00, 16.99))
bmi_ranges.append((u'Underweight', u'Mild Thinness', 17.00, 18.49))
bmi_ranges.append((u'Normal Range', u'Normal Range', 18.50, 24.99))
bmi_ranges.append((u'Overweight', u'Overweight', 25.00, 29.99))
bmi_ranges.append((u'Obese', u'Obese Class I', 30.00, 34.99))
bmi_ranges.append((u'Obese', u'Obese Class II', 35.00, 39.99))
bmi_ranges.append((u'Obese', u'Obese Class III', 40.00, 1000.00))

If a range is exactly in the list of tuples it's easy enough to just iterate through with a listcomp, but how do I find that a value is within the range of any of the other values?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

绝情姑娘 2024-10-02 08:56:54
# bmi = <whatever>
found_bmi_range = [bmi_range for bmi_range
                   in bmi_ranges
                   if bmi_ranges[2] <= bmi <= bmi_ranges[3]
                  ][0]

您可以添加 if 子句来过滤结果中包含的项目的列表推导式。

注意:您可能需要调整范围规范以使用非包含上限(即 [a,b) + [b,c) + [c,d) 等),然后将条件更改为 a <= b < c,这样就不会出现边缘情况的问题。

# bmi = <whatever>
found_bmi_range = [bmi_range for bmi_range
                   in bmi_ranges
                   if bmi_ranges[2] <= bmi <= bmi_ranges[3]
                  ][0]

You can add if clauses to list comprehensions that filter what items are included in the result.

Note: you may want to adjust your range specifications to use a non-inclusive upper bound (i.e. [a,b) + [b,c) + [c,d) et cetera), and then change the conditional to a <= b < c, that way you don't have issues with edge cases.

又爬满兰若 2024-10-02 08:56:54

您可以通过列表理解来完成此操作:

>>> result = [r for r in bmi_ranges if r[2] <= 32 <= r[3]]
>>> print result
[(u'Obese', u'Obese Class I', 30.0, 34.99)]

但是,请求数据库为您执行此操作可能会更快,否则您将请求比您需要的更多的数据。我不明白使用 BETWEEN 如何需要再使用一个数据连接。如果你能扩展它将会很有用。您是在谈论缓存数据与始终请求实时数据的优缺点吗?

您可能还想为您的数据创建一个类,以便不必将字段引用为 x[2],而是可以使用更有意义的名称。您还可以查看命名元组。

You can do this with a list comprehension:

>>> result = [r for r in bmi_ranges if r[2] <= 32 <= r[3]]
>>> print result
[(u'Obese', u'Obese Class I', 30.0, 34.99)]

However it would probably be faster to request the database to do this for you as otherwise you are requesting more data than you need. I don't understand how using a BETWEEN requires using one more data connection. If you could expand on that it would be useful. Are you talking about the pros and cons of caching data versus always asking for live data?

You may also want to create a class for your data so that you don't have to refer to fields as x[2], but instead can use more meaningful names. You could also look at namedtuples.

芯好空 2024-10-02 08:56:54

bmi = 26.2

bmi_范围 = [] bmi_ranges.append((u'体重不足', u'严重瘦弱', 0, 15.99)) bmi_ranges.append((u'体重不足', u'中等瘦度', 16.00, 16.99)) bmi_ranges.append((u'体重不足', u'轻度瘦弱', 17.00, 18.49)) bmi_ranges.append((u'正常范围', u'正常范围', 18.50, 24.99)) bmi_ranges.append((u'超重', u'超重', 25.00, 29.99)) bmi_ranges.append((u'肥胖', u'肥胖 I 级', 30.00, 34.99)) bmi_ranges.append((u'肥胖', u'肥胖 II 级', 35.00, 39.99)) bmi_ranges.append((u'Obese', u'Obese III 级', 40.00, 1000.00))

打印过滤器(lambda x: x[2] <= bmi <= x[3], bmi_ranges)


bmi = 26.2

bmi_ranges = [] bmi_ranges.append((u'Underweight', u'Severe Thinness', 0, 15.99)) bmi_ranges.append((u'Underweight', u'Moderate Thinness', 16.00, 16.99)) bmi_ranges.append((u'Underweight', u'Mild Thinness', 17.00, 18.49)) bmi_ranges.append((u'Normal Range', u'Normal Range', 18.50, 24.99)) bmi_ranges.append((u'Overweight', u'Overweight', 25.00, 29.99)) bmi_ranges.append((u'Obese', u'Obese Class I', 30.00, 34.99)) bmi_ranges.append((u'Obese', u'Obese Class II', 35.00, 39.99)) bmi_ranges.append((u'Obese', u'Obese Class III', 40.00, 1000.00))

print filter(lambda x: x[2] <= bmi <= x[3], bmi_ranges)

短叹 2024-10-02 08:56:54

如果您喜欢更轻量级的原始数据结构并从标准库导入:

import bisect

bmi_ranges = []
bmi_ranges.append((u'Underweight', u'Severe Thinness', 0, 15.99))
bmi_ranges.append((u'Underweight', u'Moderate Thinness', 16.00, 16.99))
bmi_ranges.append((u'Underweight', u'Mild Thinness', 17.00, 18.49))
bmi_ranges.append((u'Normal Range', u'Normal Range', 18.50, 24.99))
bmi_ranges.append((u'Overweight', u'Overweight', 25.00, 29.99))
bmi_ranges.append((u'Obese', u'Obese Class I', 30.00, 34.99))
bmi_ranges.append((u'Obese', u'Obese Class II', 35.00, 39.99))
bmi_ranges.append((u'Obese', u'Obese Class III', 40.00, 1000.00))

# we take just the minimal value for BMI for each class
# find the limit values between ranges:

limitValues = [line[2] for line in bmi_range][1:]
# limitValues = [16.0, 17.0, 18.5, 25.0, 30.0, 35.0, 40.0]

# bisect.bisect(list, value) returns the range
#in the list, in which value belongs
bmi_range = bmi_ranges[bisect.bisect(limitValues, bmi)]

更多信息:bisect

If you like a lighter original data structure and one import from standard library:

import bisect

bmi_ranges = []
bmi_ranges.append((u'Underweight', u'Severe Thinness', 0, 15.99))
bmi_ranges.append((u'Underweight', u'Moderate Thinness', 16.00, 16.99))
bmi_ranges.append((u'Underweight', u'Mild Thinness', 17.00, 18.49))
bmi_ranges.append((u'Normal Range', u'Normal Range', 18.50, 24.99))
bmi_ranges.append((u'Overweight', u'Overweight', 25.00, 29.99))
bmi_ranges.append((u'Obese', u'Obese Class I', 30.00, 34.99))
bmi_ranges.append((u'Obese', u'Obese Class II', 35.00, 39.99))
bmi_ranges.append((u'Obese', u'Obese Class III', 40.00, 1000.00))

# we take just the minimal value for BMI for each class
# find the limit values between ranges:

limitValues = [line[2] for line in bmi_range][1:]
# limitValues = [16.0, 17.0, 18.5, 25.0, 30.0, 35.0, 40.0]

# bisect.bisect(list, value) returns the range
#in the list, in which value belongs
bmi_range = bmi_ranges[bisect.bisect(limitValues, bmi)]

More information: bisect

只是偏爱你 2024-10-02 08:56:54

我不确定我是否理解为什么不能仅通过迭代列表来做到这一点(我知道有更有效的数据结构,但这很短,迭代会更容易理解)。出了什么问题

def check_bmi(bmi, bmi_range):
    for cls, name, a, b in bmi_range:
        if a <= bmi <= b:
            return cls # or name or whatever you need.

I'm not sure if I understand why you can't do this just by iterating over the list (I know there are more efficient datastructures, but this is very short and iteration would be more understandable). What's wrong with

def check_bmi(bmi, bmi_range):
    for cls, name, a, b in bmi_range:
        if a <= bmi <= b:
            return cls # or name or whatever you need.
百变从容 2024-10-02 08:56:54

这就是我处理它的方式:

import random

bmi_ranges = [(u'Underweight', u'Severe Thinness', 16.0),
               (u'Underweight', u'Moderate Thinness', 17.0),
               (u'Underweight', u'Mild Thinness', 18.5),
               (u'Normal Range', u'Normal Range', 25.0),
               (u'Overweight', u'Overweight', 30.0),
               (u'Obese', u'Obese Class I', 35.0),
               (u'Obese', u'Obese Class II', 40.0),
               (u'Obese', u'Obese Class III', 1000.0)]

def bmi_lookup(bmi_value):
    return next((classification, description, lessthan)
         for classification, description, lessthan in bmi_ranges
         if bmi_value < lessthan)

for bmi in range(20):
    random_bmi = random.random()*50
    print random_bmi, bmi_lookup(random_bmi)

This is how I would deal with it:

import random

bmi_ranges = [(u'Underweight', u'Severe Thinness', 16.0),
               (u'Underweight', u'Moderate Thinness', 17.0),
               (u'Underweight', u'Mild Thinness', 18.5),
               (u'Normal Range', u'Normal Range', 25.0),
               (u'Overweight', u'Overweight', 30.0),
               (u'Obese', u'Obese Class I', 35.0),
               (u'Obese', u'Obese Class II', 40.0),
               (u'Obese', u'Obese Class III', 1000.0)]

def bmi_lookup(bmi_value):
    return next((classification, description, lessthan)
         for classification, description, lessthan in bmi_ranges
         if bmi_value < lessthan)

for bmi in range(20):
    random_bmi = random.random()*50
    print random_bmi, bmi_lookup(random_bmi)
晚雾 2024-10-02 08:56:54

内置过滤器功能就是为此目的而存在的:

bmi = 26.2
answer = filter(lambda T, : T[2]<=bmi<=T[3], bmi_ranges)[0]
print answer
>>> (u'Overweight', u'Overweight', 25.0, 29.989999999999998)

希望这有帮助

The builtin filter function exists for this purpose:

bmi = 26.2
answer = filter(lambda T, : T[2]<=bmi<=T[3], bmi_ranges)[0]
print answer
>>> (u'Overweight', u'Overweight', 25.0, 29.989999999999998)

Hope this helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文