使用python itertools管理嵌套for循环

使用python itertools管理嵌套for循环,python,arrays,loops,itertools,Python,Arrays,Loops,Itertools,我正在尝试使用itertools.product管理一些嵌套for循环的簿记,其中嵌套循环的数量事先未知。下面是一个具体的例子,我选择了两个嵌套的for循环;两种选择只是为了清楚起见,我需要的是一种适用于任意数量循环的解决方案 本问题对此处出现的问题进行了扩展/概括: 现在,我使用在这里学到的itertools技巧扩展上述技术: 序言: from itertools import product def trivial_functional(i, j): return lambda x :

我正在尝试使用itertools.product管理一些嵌套for循环的簿记,其中嵌套循环的数量事先未知。下面是一个具体的例子,我选择了两个嵌套的for循环;两种选择只是为了清楚起见,我需要的是一种适用于任意数量循环的解决方案

本问题对此处出现的问题进行了扩展/概括:

现在,我使用在这里学到的itertools技巧扩展上述技术:

序言:

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,每个元素都是从平凡的函数构建的

问题:

假设给我一对整数,I_1,I_2,其中这些整数分别被解释为idx1和idx2的索引。如何使用itertools.product确定func_表数组的正确对应元素

我知道如何通过编写模仿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_表只是通过序列中某个输入的出现来索引的。您可以使用以下方法再次访问它:

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)
我建议在正确的位置使用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_表只是通过序列中某个输入的出现来索引的。您可以使用以下方法再次访问它:

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

这有点凌乱,但你看:

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>

除了自己计算外,我不知道还有什么方法可以计算平面指数。幸运的是,这并不难:

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的重塑方法与正常的多维数组索引语法结合使用

这就是它的工作原理。我们只需将func_表转换为Numpy数组,并对其进行重塑:

func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
现在,func_表不仅可用于返回单个二维点的正确函数,还可用于返回完整二维点阵列的正确函数:

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稍微重述一下这个问题,我就可以完成同样的簿记工作,并且解决我试图解决的问题,与纯python解决方案相比,速度大大提高。诀窍就是将Numpy的重塑方法与正常的多维数组索引语法结合使用

这就是它的工作原理。我们只需将func_表转换为Numpy数组,并对其进行重塑:

func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
现在,func_表不仅可用于返回单个二维点的正确函数,还可用于返回完整二维点阵列的正确函数:

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]

和往常一样,努比去营救

让我试着重新表述一下你的问题:你基本上不仅需要输入序列的元素,还需要它们的索引?是的,这是一种有效的表达方式。同样,我可以手动查看itertools的工作方式,并编写一个独立的函数来返回索引。但这似乎是不必要的重复工作,因为itertools肯定已经解决了这个问题,所以我更倾向于使用统一的itertools语法(如果可用)。第一个想法是针对产品*enumeratej for j中的项目进行联合,但这会提供您需要的信息,它的格式不一定很好……func_表中的索引是如何计算的?您声明它是一个1d数组,但有n个索引,每个输入序列一个索引。从您的代码中,每个迭代在func_表中都有自己的位置。让我试着重新表述您的问题:您基本上不仅需要输入序列的元素,还需要它们的索引?是的,这是一种有效的方式。同样,我可以手动查看itertools的工作方式,并编写一个返回索引的独立函数。但这似乎是不必要的重复工作,因为itertools肯定已经解决了这个问题,所以我更喜欢使用统一的itertools语法(如果可用的话)
在product*enumeratej中,为联合中的j计算了j,但虽然这提供了所需的信息,但格式不一定很好……func_表中的索引是如何计算的?您声明它是一个1d数组,但有n个索引,每个输入序列一个索引。从您的代码中,每个迭代在func_表中都有自己的位置。这很优雅,我认为这是处理未知嵌套程度的正确方法。它几乎肯定会慢一些。但这是python,所以我们不介意:-在您的第一个代码片段Uri中,第3行的product_index函数是什么?我认为这是一个打字错误?这是优雅的,我认为这是正确的方式来处理未知程度的嵌套。它几乎肯定会慢一些。但这是python,所以我们不介意:-在您的第一个代码片段Uri中,第3行的product_index函数是什么?我觉得这是个打字错误?