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

时间:2010-09-25 18:39:36

标签: python search tuples sequence

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

我列出了值的元组列表(见下文),当然我对任何其他数据结构都是开放的。使用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进行迭代即可,但如何找到值在任何其他值的范围内?

7 个答案:

答案 0 :(得分:2)

# 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,这样就不会出现边缘情况问题。

答案 1 :(得分:0)

您可以使用列表解析来执行此操作:

>>> 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],而是可以使用更有意义的名称。你也可以看一下namedtuples。

答案 2 :(得分:0)

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

有什么问题
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.

答案 3 :(得分:0)


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)

答案 4 :(得分:0)

这就是我要处理它的方式:

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)

答案 5 :(得分:-1)

如果您喜欢较轻的原始数据结构和一个从标准库导入:

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

答案 6 :(得分:-1)

内置过滤器功能用于此目的:

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)

希望这有帮助