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

在Python中的元组值列表中查找范围内的值,python,search,tuples,sequence,Python,Search,Tuples,Sequence,我正在尝试获得BMI值在标准BMI范围内的身体质量指数(BMI)分类-例如,如果某人的BMI为26.2,他们将在“超重”范围内 我列出了一个值的元组列表(见下文),当然我对任何其他数据结构都持开放态度。使用SQL的中间版本很容易做到这一点,但我希望在纯Python中做到这一点,主要是因为这意味着减少一个DB连接,同时也是在“纯”Python中进行更多操作的练习 如果元组列表中的某个范围正好是,那么只需使用listcomp进行迭代就很容易了,但是我如何发现某个值在任何其他值的范围内呢?\bmi=

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

我列出了一个值的元组列表(见下文),当然我对任何其他数据结构都持开放态度。使用SQL的中间版本很容易做到这一点,但我希望在纯Python中做到这一点,主要是因为这意味着减少一个DB连接,同时也是在“纯”Python中进行更多操作的练习

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

\bmi=
# bmi = <whatever>
found_bmi_range = [bmi_range for bmi_range
                   in bmi_ranges
                   if bmi_ranges[2] <= bmi <= bmi_ranges[3]
                  ][0]
找到的bmi\U范围=[bmi\U范围为bmi\U范围 在bmi_范围内
如果bmi_范围为[2],您可以通过列表理解来实现这一点:

>>> 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)]
>>结果=[r代表bmi\u范围内的r,如果r[2]>打印结果
[(u‘肥胖’,u‘肥胖一级’,30.0,34.99)]
但是,请求数据库为您执行此操作可能会更快,否则您请求的数据将超过您需要的数据量。我不明白使用中间连接如何需要使用一个以上的数据连接。如果您可以对此进行扩展,它将非常有用。您是否在谈论缓存数据与总是请求l的利弊电子数据


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

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

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.
def检查bmi(bmi,bmi范围):
对于体重指数范围内的cls、名称、a、b:
如果a<代码>
体重指数=26.2

体重指数范围=[] bmi_范围。附加((u‘体重不足’、u‘严重瘦身’、0、15.99)) bmi_范围。附加((u'体重不足',u'中等瘦',16.00,16.99)) bmi_范围。附加((u‘体重不足’、u‘轻度瘦身’、17.00、18.49)) bmi_范围。附加((u'正常范围',u'正常范围',18.50,24.99)) 体重指数范围。附加((超重、超重、25.00、29.99)) 体重指数范围。附加((u‘肥胖’,u‘肥胖一级’,30.00,34.99)) bmi_范围。附加((u'肥胖',u'肥胖二级',35.00,39.99)) 体重指数范围。附加((u‘肥胖’,u‘肥胖三级’,40.00,1000.00))


打印过滤器(lambda x:x[2]如果您喜欢更轻的原始数据结构和从标准库导入的内容:

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)]

更多信息:

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

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)
bmi=26.2
答案=过滤器(λT,:T[2]>(u'Overweight',u'Overweight',25.0,29.98999998)

希望这有帮助

我会这样处理:

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)
随机导入
bmi_范围=[(u'体重不足',u'严重瘦',16.0),
(u形“重量不足”,u形“中等厚度”,17.0),
(u形“重量不足”,u形“轻度稀薄”,18.5),
(u'正常范围',u'正常范围',25.0),
(u'超重',u'超重',30.0),
(u‘肥胖’,u‘肥胖一级’,35.0),
(u‘肥胖’,u‘肥胖二级’,40.0),
(u‘肥胖’,u‘肥胖三级’,1000.0)]
def bmi_查找(bmi_值):
返回下一个((分类、说明、小于)
用于分类、描述,小于bmi_范围
如果bmi_值
Er,你是说
a我在迭代,但这似乎是一种天真的方式,我认为我更接近“正确”使用listcomp的方法。如果数据集更大,这个解决方案的吸引力会小得多,但BMI范围是标准的,并且没有那么多值,这就是为什么我想从一开始就避免DB开销。啊,对了,amber。还有eumiro,如果BMI不在给定范围内,它将不会返回任何值。旅行可能不会更快到数据库只搜索8个范围…往返可能是最昂贵的部分…这更是完全取消往返的原因。@Amber:如果你从数据库中获取数据,你应该使用介于两者之间的方法,如果不是,那么你说的是缓存,而不是每个查询的相对速度。Caching有优点,也有缺点。@马克:范围列表很可能是恒定的,在这种情况下,它根本不会缓存,但无论您是否与DB交谈,周期,如果BMI信息来自用户。(可能不是,但这是一个完全可以想象的场景。)如果您真的关心性能,您可以使用二叉搜索树来减少比较的次数。但由于OP有sql db,因此使用适当的索引也会产生同样的效果。@eumiro-原始数据中的缺陷;可以很容易地适应
bmi_范围[2]OP对任何其他数据结构都是开放的,因此这可能是一个很好的提示,不要使用那些.99个限制值。我的答案只使用一个值来限制范围。要从下一个范围中获取最小值,您的列表理解必须稍微复杂一点。谢谢-是的,我的范围不允许更多的小数位数,但是BMI标准通常只使用小数点后1-2位,这样我就可以在BMI的赋值中四舍五入了。不过,我很想看看这在上限或下限下是如何工作的(对分解比列表理解要慢得多,@eumiro)。为什么要使用listcomp执行此操作?现在,在列表理解中使用
if
子句是执行此操作的首选方法;筛选器仍然可用,但不是首选方法。@eumiro:29.995将不属于任何范围,因为@JoughDempsey将范围括起来。29.995>29。99@Amber:你能解释一下为什么要列出这个清单吗理解的if语句i
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)
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)