简体   繁体   English

使用递归计算数组组合

[英]Calculating array combinations using recursion

I wish to input an n*m array and the resulting output be an array containing the different combinations of the row elements. 我希望输入一个n * m数组,结果输出是一个包含行元素的不同组合的数组。 Here's an example to clarify (albeit an extremely simple case): 这是一个澄清的例子(尽管是一个非常简单的例子):

I wish to input an array of the following shape: 我希望输入以下形状的数组:

[[1, 2, 3]
[2, 5, 6]]

And wish to receive the following output: 并希望收到以下输出:

[[1,2], [1,5], [1,6], [2,5], [2,6], [3,2], [3,5], [3,6]]

As you can see [2,2] is not included because of repetition. 正如您所见, [2,2]因重复而未包括在内。

I can write quick and dirty code containing nested for loops when the input dimensions are know a priori: 当输入维度先验地知道时,我可以编写包含嵌套for循环的快速和脏代码:

A = [[1, 2, 3], [2, 5, 6]]
m = len(A[0])    
for i in range(0, m):      
    for j in range(0, m):
            if A[0][i]!=A[1][j]:                     #check and eliminate repetition
                combined.append([A[0][i],A[1][j])
                choice_num.append([i+1, j+1])    #See (**) below

I would really like to know how to implement this as a recursive function so given some input nD array, A, one can simply call it as: 我真的想知道如何将其作为递归函数实现,因此给定一些输入nD数组A,可以简单地将其称为:

recursive_looper(A)

(**) Another feature that I would like is for the function to output the column number corresponding to the element used in the combination so we get two outputs: (**)我想要的另一个功能是函数输出与组合中使用的元素相对应的列号,因此我们得到两个输出:

element values:   [[1,2], [1,5], [1,6], [2,5], [2,6], [3,2], [3,5], [3,6]]
element position: [[1,1], [1,2], [1,3], [2,2], [2,3], [3,1], [3,2], [3,3]]

Any tips or suggestions would be greatly appreciated!! 任何提示或建议将不胜感激!!

Edit: I am open to any solution that can achieve the desired output. 编辑:我对任何可以实现所需输出的解决方案持开放态度。 Recursion was simply the first thing that came to mind. 递归只是我想到的第一件事。

Edit 2 (Extended capabilities): This code must not be restricted to a specific list input shape but be extensible to any array of shape (n,m). 编辑2(扩展功能):此代码不得限制为特定的列表输入形状,而是可扩展为任何形状(n,m)数组。 I'll provide an example for where the code breaks down. 我将提供代码中断的示例。 The work-around was implementing n-1 conditional statements, which I would like to avoid because the array shape must be known a priori. 解决方法是实现n-1个条件语句, 我想避免使用它,因为数组形状必须是先验已知的。

A = [[2, 4, 1, 11, 3], [3, 2, 1, 4, 11], [2, 3, 4, 17, 13]]

If I do not make any modifications to your indexing/filter I receive the following output for the 'filtered' list: 如果我不对您的索引/过滤器进行任何修改,我会收到“过滤”列表的以下输出:

#[[2, 3, 2], [2, 3, 3], [2, 3, 4], [2, 3, 17], [2, 3, 13], [2, 1, 2], ..., [3, 11, 13]]

Immediately I notice that it only compared element position 0 with position 1 for 'likeness', hence why the first combination contains two 2's. 我立刻注意到它只将元素位置0和位置1比较为“相似度”,因此第一个组合包含两个2的原因。 I can make a modification to the Index grabber and filter loop which looks like so: 我可以修改索引抓取器和过滤器循环,如下所示:

for i in range(0, len(projects_master)-2):
    indexes = [idx for idx, t in enumerate(prod) if t[i] == t[i+1] or t[i]==t[i+2] or t[i+1] == t[i+2] ]

res = []
for i in range(0, len(A)-2):
    res.append(list(filter( lambda v: v[i] != v[i+1] and v[i] != v[i+2] and v[i+1] != v[i+2], prod)))
result = [list(t) for t in res[0]]

This does give the correct output, but like I said, I needed to write out n-1 t[i] and v[i] conditions. 确实给出了正确的输出,但就像我说的那样,我需要写出n-1 t [i]和v [i]条件。 How can this be done automatically? 怎么能自动完成?

EDIT 3 - FINAL Thanks a bunch to those who provided different approaches to help me achieve the same end goal. 编辑3 - 最终感谢那些提供不同方法帮助我实现相同目标的人。 I took some insight from each and wrote something that makes sense to me and seems to function well for any input. 我从每个人那里获得了一些见解并写了一些对我有意义的东西,似乎对任何输入都有效。 The code which filters duplicates and removes them from the combinations is shown below: 过滤重复项并从组合中删除它们的代码如下所示:

ind_remove = []
for i in range(0, len(prod)):
    if len(prod[i]) != len(set(prod[i])):
        ind_remove.append(i)

adder=0
for i in ind_remove:
    del prod[i-adder]
    adder=adder+1   #takes into account change in indices after an element is deleted.

You can use itertools.product to generate the required combinations, which works like a cartesion product between two sets to generate the combinations. 您可以使用itertools.product生成所需的组合,其作用类似于两组之间的cartesion产品以生成组合。

So it the lists have been [[1, 2], [3, 4]] , the cartesian product within the sublists will be 所以列表已经[[1, 2], [3, 4]] ,子列表中的笛卡尔积将是
[[1, 3], [1, 4], [2, 3], [2, 4]]

from itertools import product

a = [[1, 2, 3], [2, 5, 6]]

# Generate all possible products, *a gives you two lists
prod = list(product(*a))
#[(1, 2), (1, 5), (1, 6), (2, 2), (2, 5), (2, 6), (3, 2), (3, 5), (3, 6)]

#Get the list of duplicate indexes
indexes = [idx for idx, t in enumerate(prod) if t[0] == t[1] ]
print(indexes)
#[3]

#Remove tuples who are duplicates
res = list(filter( lambda v: v[0] != v[1], prod))
print(res)
#[(1, 2), (1, 5), (1, 6), (2, 5), (2, 6), (3, 2), (3, 5), (3, 6)]

#Convert the tuples to list
result = [list(t) for t in res]
print(result)
#[[1, 2], [1, 5], [1, 6], [2, 5], [2, 6], [3, 2], [3, 5], [3, 6]]

You can use a function that iterates over the items of the first list of the given list of lists and merge each item with the combinations from the recursive calls: 您可以使用迭代给定列表列表的第一个列表的项目的函数,并将每个项目与递归调用的组合合并:

def nonrepetitive_product(lists):
    if not lists:
        yield []
        return
    first, *rest = lists
    combinations = list(nonrepetitive_product(rest))
    for item in first:
        for combination in combinations:
            if item not in combination:
                yield [item, *combination]

so that given: 所以给出:

l = [[1, 2, 3], [2, 5, 6]]

list(nonrepetitive_product(l)) returns: list(nonrepetitive_product(l))返回:

[[1, 2], [1, 5], [1, 6], [2, 5], [2, 6], [3, 2], [3, 5], [3, 6]]

If you want the positions and values for any number of rows, you'd be better off using itertools.product and enumerate together. 如果你想要任意数量的行的位置和值,你最好使用itertools.product并一起enumerate Filtering is a little tricky, but it can be done: 过滤有点棘手,但可以做到:

import itertools

A = [[1, 2, 3], [2, 5, 6], [7, 8, 3]]

prod = itertools.product(*map(enumerate, A))     # yields ((i,x),(j,y),(k,z),...) nested tuples
transposed = ([*zip(*pairs)] for pairs in prod)  # yields ((i,j,k,...), (x,y,z,...)) 2-tuples
filtered = [(ijk, xyz) for ijk, xyz in transposed if len(xyz) == len(set(xyz))] # filter dupes

indexes, values = zip(*filtered) # you might find `filtered` more useful than separate lists

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

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