比 if-elif 语句更快
Faster than if-elif statement
我正在从传感器实时接收大量点数。但是,我只需要 4 类点,即 top_left、top_right、bottom_left 和 bottom_right。我在 Python 2 中有一个 if-elif 语句如下:
from random import random, randint
# points below are received from sensor. however,
# here in this post I am creating it randomly.
points = [Point(randint(0, i), random(), random(), random()) for i in range(100)]
# 4 categories
top_left, top_right, bottom_left, bottom_right = None, None, None, None
for p in points:
if p.id == 5:
top_left = p
elif p.id == 7:
top_right = p
elif p.id == 13:
bottom_left = p
elif p.id == 15:
bottom_right = p
print top_left.id, top_left.x, top_left.y, top_left.z # check variable
每个点都有一个 id 和 x, y, z 参数。这是一个内置的 class。我只是在这里展示一个示例 class。
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
是否有任何有效的方法来考虑实现相同的运行时间。
答案:
我正在添加从答案中得到的结果。似乎 是最快的。下面是我的测试代码:
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
from random import random, randint
n = 1000
points = [Point(randint(0, i), random(), random(), random()) for i in range(n)]
def method1():
top_left, top_right, bottom_left, bottom_right = None, None, None, None
for p in points:
if p.id == 5:
top_left = p
elif p.id == 7:
top_right = p
elif p.id == 13:
bottom_left = p
elif p.id == 15:
bottom_right = p
#print top_left.id, top_left.x, top_left.y, top_left.z
def method2():
categories = {
5: None, # top_left
7: None, # top_right
13: None, # bottom_left
15: None # bottom_right
}
for p in points:
categories[p.id] = p
top_left = categories[5]
#print top_left.id, top_left.x, top_left.y, top_left.z
def method3():
name_to_id = {'top_left': 5, 'top_right': 7, 'bottom_left': 13, 'bottom_right': 15}
ids = [value for value in name_to_id.values()]
bbox = {id: None for id in ids}
for point in points:
try:
bbox[point.id] = Point(point.id, point.x, point.y, point.z)
except KeyError: # Not an id of interest.
pass
top_left = bbox[name_to_id['top_left']]
#print top_left.id, top_left.x, top_left.y, top_left.z
from timeit import Timer
print 'method 1:', Timer(lambda: method1()).timeit(number=n)
print 'method 2:', Timer(lambda: method2()).timeit(number=n)
print 'method 3:', Timer(lambda: method3()).timeit(number=n)
查看下面返回的输出:
ravi@home:~/Desktop$ python test.py
method 1: 0.174991846085
method 2: 0.0743980407715
method 3: 0.582262039185
而不是使用列表理解:
points = [Point(randint(0, i), random(), random(), random()) for i in range(100)]
在创建过程中使用循环并分配点:
points = []
for i in range(100):
p = Point(randint(0, i), random(), random(), random())
points.append(p)
if p.id == 5:
top_left = p
elif p.id == 7:
top_right = p
elif p.id == 13:
bottom_left = p
elif p.id == 15:
bottom_right = p
这样你就可以在一次而不是两次迭代中完成所有工作。
您可以使用字典来保存对象。 Dict在键查找方面非常高效
使用 dict 的速度是使用 if else 块的两倍。
这是python中最有效的方式:
from random import random, randint
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
# points below are received from sensor. however,
# here in this post I am creating it randomly.
points = [Point(randint(0, i), random(), random(), random()) for i in
range(100)]
# 4 categories
categories = {
5: None, # top_left
7: None, # top_right
13: None, # bottom_left
15: None # bottom_right
}
for p in points:
categories[p.id] = p
>>> print categories[5].id, categories[5].x, categories[5].y, categories[5].z # check variable
5 0.516239541892 0.935096344266 0.0859987803457
这是一种应该更快的方法,因为它使用单个 if
来确定 Point
是否是基于 id
属性的极端值之一,加上if
使用非常快的字典 in
操作进行成员测试。本质上,bbox
字典预加载了对应于所寻找的四个 id 的键,这使得检查其中的 any 成为一个相对有效的操作。
请注意,如果 Point
列表中有重复的 id
点,最后看到的点将被选中。还要注意,如果没有找到匹配 id
的点,一些最终变量的值将是 None
而不是 Point
实例。
from random import randint, random
from pprint import pprint
from operator import attrgetter
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
points = [Point(randint(0, 20), random(), random(), random()) for i in range(100)]
name_to_id = {'top_left': 5, 'top_right': 7, 'bottom_left': 13, 'bottom_right': 15}
bbox = {id: None for id in name_to_id.values()} # Preload with ids of interest.
for point in points:
if point.id in bbox: # id of interest?
bbox[point.id] = point
# Assign bbox's values to variables with meaningful names.
top_left = bbox[name_to_id['top_left']]
top_right = bbox[name_to_id['top_right']]
bottom_left = bbox[name_to_id['bottom_left']]
bottom_right = bbox[name_to_id['bottom_right']]
for point in [top_left, top_right, bottom_left, bottom_right]:
print('Point({}, {}, {}, {})'.format(point.id, point.x, point.y, point.z))
我正在从传感器实时接收大量点数。但是,我只需要 4 类点,即 top_left、top_right、bottom_left 和 bottom_right。我在 Python 2 中有一个 if-elif 语句如下:
from random import random, randint
# points below are received from sensor. however,
# here in this post I am creating it randomly.
points = [Point(randint(0, i), random(), random(), random()) for i in range(100)]
# 4 categories
top_left, top_right, bottom_left, bottom_right = None, None, None, None
for p in points:
if p.id == 5:
top_left = p
elif p.id == 7:
top_right = p
elif p.id == 13:
bottom_left = p
elif p.id == 15:
bottom_right = p
print top_left.id, top_left.x, top_left.y, top_left.z # check variable
每个点都有一个 id 和 x, y, z 参数。这是一个内置的 class。我只是在这里展示一个示例 class。
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
是否有任何有效的方法来考虑实现相同的运行时间。
答案:
我正在添加从答案中得到的结果。似乎
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
from random import random, randint
n = 1000
points = [Point(randint(0, i), random(), random(), random()) for i in range(n)]
def method1():
top_left, top_right, bottom_left, bottom_right = None, None, None, None
for p in points:
if p.id == 5:
top_left = p
elif p.id == 7:
top_right = p
elif p.id == 13:
bottom_left = p
elif p.id == 15:
bottom_right = p
#print top_left.id, top_left.x, top_left.y, top_left.z
def method2():
categories = {
5: None, # top_left
7: None, # top_right
13: None, # bottom_left
15: None # bottom_right
}
for p in points:
categories[p.id] = p
top_left = categories[5]
#print top_left.id, top_left.x, top_left.y, top_left.z
def method3():
name_to_id = {'top_left': 5, 'top_right': 7, 'bottom_left': 13, 'bottom_right': 15}
ids = [value for value in name_to_id.values()]
bbox = {id: None for id in ids}
for point in points:
try:
bbox[point.id] = Point(point.id, point.x, point.y, point.z)
except KeyError: # Not an id of interest.
pass
top_left = bbox[name_to_id['top_left']]
#print top_left.id, top_left.x, top_left.y, top_left.z
from timeit import Timer
print 'method 1:', Timer(lambda: method1()).timeit(number=n)
print 'method 2:', Timer(lambda: method2()).timeit(number=n)
print 'method 3:', Timer(lambda: method3()).timeit(number=n)
查看下面返回的输出:
ravi@home:~/Desktop$ python test.py
method 1: 0.174991846085
method 2: 0.0743980407715
method 3: 0.582262039185
而不是使用列表理解:
points = [Point(randint(0, i), random(), random(), random()) for i in range(100)]
在创建过程中使用循环并分配点:
points = []
for i in range(100):
p = Point(randint(0, i), random(), random(), random())
points.append(p)
if p.id == 5:
top_left = p
elif p.id == 7:
top_right = p
elif p.id == 13:
bottom_left = p
elif p.id == 15:
bottom_right = p
这样你就可以在一次而不是两次迭代中完成所有工作。
您可以使用字典来保存对象。 Dict在键查找方面非常高效
使用 dict 的速度是使用 if else 块的两倍。
这是python中最有效的方式:
from random import random, randint
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
# points below are received from sensor. however,
# here in this post I am creating it randomly.
points = [Point(randint(0, i), random(), random(), random()) for i in
range(100)]
# 4 categories
categories = {
5: None, # top_left
7: None, # top_right
13: None, # bottom_left
15: None # bottom_right
}
for p in points:
categories[p.id] = p
>>> print categories[5].id, categories[5].x, categories[5].y, categories[5].z # check variable
5 0.516239541892 0.935096344266 0.0859987803457
这是一种应该更快的方法,因为它使用单个 if
来确定 Point
是否是基于 id
属性的极端值之一,加上if
使用非常快的字典 in
操作进行成员测试。本质上,bbox
字典预加载了对应于所寻找的四个 id 的键,这使得检查其中的 any 成为一个相对有效的操作。
请注意,如果 Point
列表中有重复的 id
点,最后看到的点将被选中。还要注意,如果没有找到匹配 id
的点,一些最终变量的值将是 None
而不是 Point
实例。
from random import randint, random
from pprint import pprint
from operator import attrgetter
class Point():
def __init__(self, id, x, y, z):
self.id = id
self.x = x
self.y = y
self.z = z
points = [Point(randint(0, 20), random(), random(), random()) for i in range(100)]
name_to_id = {'top_left': 5, 'top_right': 7, 'bottom_left': 13, 'bottom_right': 15}
bbox = {id: None for id in name_to_id.values()} # Preload with ids of interest.
for point in points:
if point.id in bbox: # id of interest?
bbox[point.id] = point
# Assign bbox's values to variables with meaningful names.
top_left = bbox[name_to_id['top_left']]
top_right = bbox[name_to_id['top_right']]
bottom_left = bbox[name_to_id['bottom_left']]
bottom_right = bbox[name_to_id['bottom_right']]
for point in [top_left, top_right, bottom_left, bottom_right]:
print('Point({}, {}, {}, {})'.format(point.id, point.x, point.y, point.z))