简体   繁体   English

生成在每个元素上遵循特定条件的n尺寸向量的所有可能组合

[英]Generating all possible combinations of n-sized vector that follow certain conditions on each element

I have a list d of length r such that d = (d_1, d_2,..., d_r) . 我有一个长度为r的列表d,使得d = (d_1, d_2,..., d_r) I would like to generate all possible vectors of length r such that for any i (from 0 to r), v_i is between 0 and d_i . 我想生成所有可能的长度为r的向量,以便for any i (from 0 to r), v_i is between 0 and d_i

For example, 例如,

if r =2 and d= (1,2), v_1 can be 0 or 1 and v_2 can be 0,1 or 2. 

Hence there are 6 possible vectors: [0,0] , [0,1], [0,2], [1,0] , [1,1], [1,2] 因此,有6种可能的向量: [0,0] , [0,1], [0,2], [1,0] , [1,1], [1,2]

I have looked into Itertools and combinations and I have a feeling I will have to use recursion however I have not managed to solve it yet and was hoping for some help or advice into the right direction. 我已经研究了Itertools及其组合,我有一种感觉,我将不得不使用递归,但是我还没有设法解决它,并希望向正确的方向寻求帮助或建议。

Edit: I have written the following code for my problem and it works however I did it in a very inefficient way by disregarding the condition and generating all possible vectors then pruning the invalid ones. 编辑:我为我的问题写了以下代码, 它可以工作,但是我通过忽略条件并生成所有可能的向量然后修剪无效的向量,以非常低效的方式做到了。 I took the largest d_i and generated all vectors of size r from (0,0,...0) all the way to (max_d_i,max_d_i,....max_d_i) and then eliminated those that were invalid. 我取了最大的d_i并从(0,0,...0)一直到(max_d_i,max_d_i,....max_d_i)生成了所有大小为r向量,然后消除了那些无效的(max_d_i,max_d_i,....max_d_i)

Code: 码:

import itertools
import copy
def main(d):
    arr = []
    correct_list =[]
    curr = []
    r= len(d)
    greatest = max(d)
    for i in range(0,greatest+1):
        arr = arr + [i]
    #all_poss_arr is a list that holds all possible vectors of length r from (0,0,...,0) to (max,max,...,max)
    # for example if greatest was 3 and r= 4, all_poss_arr would have (0,0,0,0), then (0,0,0,1) and so on,
    #all the way to (3,3,3,3)
    all_poss_arr = list(itertools.product(arr,repeat = r))    
    #Now I am going to remove all the vectors that dont follow the v_i is between 0 and d_i
    for i in range(0,len(all_poss_arr)):
        curr = all_poss_arr[i]
        cnt = 0
        for j in range(0,len(curr)):
            if curr[j] <= d[j]:
                cnt = cnt +1
        if cnt == r:
            curr = list(curr)
            currcopy = copy.copy(curr)
            correct_list = correct_list + [currcopy]
            cnt =0
    return correct_list

If anyone knows a better way, let me know, it is much appreciated. 如果有人知道更好的方法,请告诉我,我们将不胜感激。

You basically want a Cartesian product. 您基本上需要笛卡尔积。 I'll demonstrate a basic, functional and iterative approach. 我将演示一种基本,功能和迭代的方法。

Given 给定

import operator as op
import functools as ft
import itertools as it


def compose(f, g):
    """Return a function composed of two functions."""
    def h(*args, **kwargs):
        return f(g(*args, **kwargs))
    return h


d = (1, 2)

Code

Option 1: Basic - Manual Unpacking 选项1:基本-手动拆箱

list(it.product(range(d[0] + 1), range(d[1] + 1)))
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

Option 2: Functional - Automated Mapping 选项2:功能-自动映射

def vector_combs(v):
    """Return a Cartesian product of unpacked elements from `v`."""
    plus_one = ft.partial(op.add, 1)
    range_plus_one = compose(range, plus_one)
    res = list(it.product(*map(range_plus_one, v)))
    return res


vector_combs(d)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

Option 3: Iterative - Range Replication (Recommended) 选项3:迭代-范围复制(推荐)

list(it.product(*[range(x + 1) for x in d]))
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

Details 细节

Option 1 选项1

The basic idea is illustrated in Option 1: 基本思想在选项1中说明:

Note, each range is manually incremented and passed in as an index from d . 注意,每个范围都是手动递增的,并作为d的索引传递 We automate these limitations in with the last options. 我们在最后的选项中自动实现了这些限制。

Option 2 选项2

We apply a functional approach to handle the various arguments and functions: 我们采用一种功能方法来处理各种参数和功能:

  • Partial the 1 argument to the add() function. 将部分 1参数传递给add()函数。 This returns a function that will increment any number. 这将返回一个将递增任何数字的函数。
  • Let's pass this function into range through composition . 让我们将此功能传递给composition range This allows us to have a modified range function that auto increments the integer passed in. 这使我们可以使用修改后的范围函数,该函数会自动递增传入的整数。
  • Finally we map the latter function to each element in tuple d . 最后,我们将后一个函数映射到元组d每个元素。 Now d works with any length r . 现在d可以使用任何长度r

Example ( d = (1, 2, 1), r = 3 ): 例子( d = (1, 2, 1), r = 3 ):

vector_combs((1, 2, 1))
# [(0, 0, 0),
#  (0, 0, 1),
#  (0, 1, 0),
#  (0, 1, 1),
#  (0, 2, 0),
#  (0, 2, 1),
#  (1, 0, 0),
#  (1, 0, 1),
#  (1, 1, 0),
#  (1, 1, 1),
#  (1, 2, 0),
#  (1, 2, 1)]

Option 3 选项3

Perhaps most elegantly, just use a list comprehension to create r ranges. 也许最优雅的做法是,仅使用列表推导来创建r范围。 ;) ;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM