使用 python itertools 来管理嵌套的 for 循环
using python itertools to manage nested for loops
我正在尝试使用 itertools.product 来管理一些嵌套 for 循环的簿记,其中嵌套循环的数量是事先不知道的。下面是一个具体的例子,我选择了两个嵌套的 for 循环;选择两个只是为了清楚起见,我需要的是一个适用于任意数量循环的解决方案。
此问题提供了此处出现的问题的 extension/generalization:
现在我正在使用我在此处学到的 itertools 技巧扩展上述技术:
Iterating over an unknown number of nested loops in python
序言:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
在上面的 itertools 循环结束时,我有一个 12 元素的一维函数数组,func_table,每个元素都是从trivial_functional。
问题:
假设我得到一对整数,(i_1, i_2),其中这些整数将被解释为 idx1 的索引和 idx2。如何使用 itertools.product 确定 func_table 数组的正确对应元素?
我知道如何通过编写我自己的模仿 itertools.product 簿记的函数来破解答案,但肯定有 itertools.product 的内置功能正是用于此目的?
我建议在正确的地方使用 enumerate()
:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
根据我从您的评论和代码中了解到的情况,func_table
只是根据序列中某个输入的出现进行索引。您可以使用以下方式再次访问它:
for index, items in enumerate(product(*joint)):
# because of the append(), index is now the
# position of the function created from the
# respective tuple in join()
func_table[index](some_value)
这有点乱,但是给你:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [enumerate(idx1), enumerate(idx2)]
func_map = {}
for indexes, items in map(lambda x: zip(*x), product(*joint)):
f = trivial_functional(*items)
func_map[indexes] = f
print(func_map[(2, 0)](5)) # 40 = (3+5)*5
除了自己计算外,我不知道有什么方法可以计算平面指数。幸运的是这并不难:
def product_flat_index(factors, indices):
if len(factors) == 1: return indices[0]
else: return indices[0] * len(factors[0]) + product_flat_index(factors[1:], indices[1:])
>> product_flat_index(joint, (2, 1))
9
另一种方法是首先将结果存储在 嵌套 数组中,这样就无需进行转换,尽管这更复杂:
from functools import reduce
from operator import getitem, setitem, itemgetter
def get_items(container, indices):
return reduce(getitem, indices, container)
def set_items(container, indices, value):
c = reduce(getitem, indices[:-1], container)
setitem(c, indices[-1], value)
def initialize_table(lengths):
if len(lengths) == 1: return [0] * lengths[0]
subtable = initialize_table(lengths[1:])
return [subtable[:] for _ in range(lengths[0])]
func_table = initialize_table(list(map(len, joint)))
for items in product(*map(enumerate, joint)):
f = trivial_functional(*map(itemgetter(1), items))
set_items(func_table, list(map(itemgetter(0), items)), f)
>>> get_items(func_table, (2, 1)) # same as func_table[2][1]
<function>
这么多的回答还是很有用的,感谢大家的解答。
事实证明,如果我用 Numpy 稍微重写问题,我可以完成相同的簿记,并以相对于纯 python 解决方案大大提高的速度解决我试图解决的问题。诀窍就是将 Numpy 的 reshape 方法与正常的多维数组索引语法一起使用。
这是它的工作原理。我们只是将 func_table 转换为 Numpy 数组,并对其进行整形:
func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
现在 func_table 可用于 return 正确的功能,不仅适用于单个 2d 点,而且适用于完整的 2d 点阵列:
dim1_pts = [3,1,2,1,3,3,1,3,0]
dim2_pts = [0,1,2,1,2,0,1,2,1]
func_array = func_table[dim1_pts, dim2_pts]
像往常一样,Numpy 来拯救!
我正在尝试使用 itertools.product 来管理一些嵌套 for 循环的簿记,其中嵌套循环的数量是事先不知道的。下面是一个具体的例子,我选择了两个嵌套的 for 循环;选择两个只是为了清楚起见,我需要的是一个适用于任意数量循环的解决方案。
此问题提供了此处出现的问题的 extension/generalization:
现在我正在使用我在此处学到的 itertools 技巧扩展上述技术: Iterating over an unknown number of nested loops in python
序言:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
在上面的 itertools 循环结束时,我有一个 12 元素的一维函数数组,func_table,每个元素都是从trivial_functional。
问题:
假设我得到一对整数,(i_1, i_2),其中这些整数将被解释为 idx1 的索引和 idx2。如何使用 itertools.product 确定 func_table 数组的正确对应元素?
我知道如何通过编写我自己的模仿 itertools.product 簿记的函数来破解答案,但肯定有 itertools.product 的内置功能正是用于此目的?
我建议在正确的地方使用 enumerate()
:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
根据我从您的评论和代码中了解到的情况,func_table
只是根据序列中某个输入的出现进行索引。您可以使用以下方式再次访问它:
for index, items in enumerate(product(*joint)):
# because of the append(), index is now the
# position of the function created from the
# respective tuple in join()
func_table[index](some_value)
这有点乱,但是给你:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [enumerate(idx1), enumerate(idx2)]
func_map = {}
for indexes, items in map(lambda x: zip(*x), product(*joint)):
f = trivial_functional(*items)
func_map[indexes] = f
print(func_map[(2, 0)](5)) # 40 = (3+5)*5
除了自己计算外,我不知道有什么方法可以计算平面指数。幸运的是这并不难:
def product_flat_index(factors, indices):
if len(factors) == 1: return indices[0]
else: return indices[0] * len(factors[0]) + product_flat_index(factors[1:], indices[1:])
>> product_flat_index(joint, (2, 1))
9
另一种方法是首先将结果存储在 嵌套 数组中,这样就无需进行转换,尽管这更复杂:
from functools import reduce
from operator import getitem, setitem, itemgetter
def get_items(container, indices):
return reduce(getitem, indices, container)
def set_items(container, indices, value):
c = reduce(getitem, indices[:-1], container)
setitem(c, indices[-1], value)
def initialize_table(lengths):
if len(lengths) == 1: return [0] * lengths[0]
subtable = initialize_table(lengths[1:])
return [subtable[:] for _ in range(lengths[0])]
func_table = initialize_table(list(map(len, joint)))
for items in product(*map(enumerate, joint)):
f = trivial_functional(*map(itemgetter(1), items))
set_items(func_table, list(map(itemgetter(0), items)), f)
>>> get_items(func_table, (2, 1)) # same as func_table[2][1]
<function>
这么多的回答还是很有用的,感谢大家的解答。
事实证明,如果我用 Numpy 稍微重写问题,我可以完成相同的簿记,并以相对于纯 python 解决方案大大提高的速度解决我试图解决的问题。诀窍就是将 Numpy 的 reshape 方法与正常的多维数组索引语法一起使用。
这是它的工作原理。我们只是将 func_table 转换为 Numpy 数组,并对其进行整形:
func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
现在 func_table 可用于 return 正确的功能,不仅适用于单个 2d 点,而且适用于完整的 2d 点阵列:
dim1_pts = [3,1,2,1,3,3,1,3,0]
dim2_pts = [0,1,2,1,2,0,1,2,1]
func_array = func_table[dim1_pts, dim2_pts]
像往常一样,Numpy 来拯救!