具有数量的项目的排列

时间:2018-05-08 17:49:36

标签: python math permutation

使用python我必须使用python获取给定子集的所有排列。 我使用了itertools.permutation,但结果有点不同。

想想一台机器,它有最大的容量,我们的产品可以一起生产,我们必须填补机器的容量。

输出格式并不重要,我用字典来描述它。我会在得到这些组合后进行计算。

例如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct charact {
    char ch;
    int occurs;
    struct charact *next;
};

typedef struct charact Char;
typedef Char * ListofChar;
typedef Char * CharNode_ptr;
void letters(char name[50], ListofChar * chars_ptr);
void report(ListofChar chars);
Char * createnode(char ch);


int main() {
    char name[50];
    ListofChar chars = NULL;
    scanf("%s", name);
    letters(name,&chars);
    report(chars);
    return 0;
}


Char * createnode(char ch) {
    CharNode_ptr newnode_ptr ;
    newnode_ptr = malloc(sizeof (Char));
    newnode_ptr -> ch = ch;
    newnode_ptr -> occurs = 0;
    newnode_ptr -> next = NULL;
    return newnode_ptr;
}


void letters(char name[50],ListofChar* lst_ptr){
    ListofChar newnode ;
    newnode =(Char*)malloc(sizeof(Char));
    if(!newnode){printf("adinamia mnimis");}
    int i,j;

    for( i = 0 ; i < strlen(name)  ; i++){
        newnode->ch  = name[i] ;
        printf("Look: %c\n",newnode->ch);
        newnode->next = *lst_ptr ;
        *lst_ptr = newnode ;
        }

    for( i = 0 ; i < 50 ; i++){
        for( j = 0 ; j < strlen(name) ; j++){
            if  (newnode->ch == name[i]){
                newnode->occurs++;
                printf("uhm : %c\n",newnode->ch) ;
                newnode = newnode->next;
                break;
                }
            printf("hey : %c\n",newnode->ch);
        }
    }

}




void report(ListofChar chars) {
    ListofChar current  ;
    current = chars ;
    printf("the occurences of each letter are:\n");
    while(current != NULL){
        printf("%c :  %d\n", current->ch,current->occurs );
        current = current->next ;
    }
    if(current==NULL)printf("fail");
    return;
}

我们不想要重复元素:

products = {'x','y','z','a'}
machine_capcacity = 8
#required output as follows:
{'x':5,'y':1,'z':1,'a':1}

{'x':4,'y':2,'z':1,'a':1}
{'x':4,'y':1,'z':2,'a':1}
{'x':4,'y':1,'z':1,'a':2}

{'x':3,'y':3,'z':1,'a':1}
{'x':3,'y':1,'z':3,'a':1}
{'x':3,'y':1,'z':1,'a':3}

{'x':3,'y':2,'z':2,'a':1}
{'x':3,'y':2,'z':1,'a':2}
{'x':3,'y':1,'z':2,'a':2}

{'x':2,'y':4,'z':1,'a':1}
# ...

{'x':6,'y':1,'z':1} # This can't be in results,since need at least 1 element of product
{'x':4,'y':1,'z':1,'a':1} # This can't be in results,since we need to fill the capacity

{'x':5,'y':1,'z':1,'a':1}

对我们来说是一回事。

2 个答案:

答案 0 :(得分:1)

您可以使用递归函数查找range(machine_capacity)中值的所有可能组合,这两种值的总和为8并且是唯一的。然后,products中的元素可以映射到找到的组合的子列表中的每个元素:

products = ['x','y','z','a']
machine_capacity = 8
def combinations(d, current = []):
  if len(current) == len(products):
    yield current
  else:
    for i in range(machine_capacity):
       if sum(current+[i]) <= machine_capacity:
         yield from combinations(d, current+[i])

data = [dict(zip(products, i)) for i in filter(lambda x:sum(x) == 8 and len(x) == len(set(x)), combinations(machine_capacity))]

输出:

[{'a': 5, 'x': 0, 'z': 2, 'y': 1}, {'a': 4, 'x': 0, 'z': 3, 'y': 1}, {'a': 3, 'x': 0, 'z': 4, 'y': 1}, {'a': 2, 'x': 0, 'z': 5, 'y': 1}, {'a': 5, 'x': 0, 'z': 1, 'y': 2}, {'a': 1, 'x': 0, 'z': 5, 'y': 2}, {'a': 4, 'x': 0, 'z': 1, 'y': 3}, {'a': 1, 'x': 0, 'z': 4, 'y': 3}, {'a': 3, 'x': 0, 'z': 1, 'y': 4}, {'a': 1, 'x': 0, 'z': 3, 'y': 4}, {'a': 2, 'x': 0, 'z': 1, 'y': 5}, {'a': 1, 'x': 0, 'z': 2, 'y': 5}, {'a': 5, 'x': 1, 'z': 2, 'y': 0}, {'a': 4, 'x': 1, 'z': 3, 'y': 0}, {'a': 3, 'x': 1, 'z': 4, 'y': 0}, {'a': 2, 'x': 1, 'z': 5, 'y': 0}, {'a': 5, 'x': 1, 'z': 0, 'y': 2}, {'a': 0, 'x': 1, 'z': 5, 'y': 2}, {'a': 4, 'x': 1, 'z': 0, 'y': 3}, {'a': 0, 'x': 1, 'z': 4, 'y': 3}, {'a': 3, 'x': 1, 'z': 0, 'y': 4}, {'a': 0, 'x': 1, 'z': 3, 'y': 4}, {'a': 2, 'x': 1, 'z': 0, 'y': 5}, {'a': 0, 'x': 1, 'z': 2, 'y': 5}, {'a': 5, 'x': 2, 'z': 1, 'y': 0}, {'a': 1, 'x': 2, 'z': 5, 'y': 0}, {'a': 5, 'x': 2, 'z': 0, 'y': 1}, {'a': 0, 'x': 2, 'z': 5, 'y': 1}, {'a': 1, 'x': 2, 'z': 0, 'y': 5}, {'a': 0, 'x': 2, 'z': 1, 'y': 5}, {'a': 4, 'x': 3, 'z': 1, 'y': 0}, {'a': 1, 'x': 3, 'z': 4, 'y': 0}, {'a': 4, 'x': 3, 'z': 0, 'y': 1}, {'a': 0, 'x': 3, 'z': 4, 'y': 1}, {'a': 1, 'x': 3, 'z': 0, 'y': 4}, {'a': 0, 'x': 3, 'z': 1, 'y': 4}, {'a': 3, 'x': 4, 'z': 1, 'y': 0}, {'a': 1, 'x': 4, 'z': 3, 'y': 0}, {'a': 3, 'x': 4, 'z': 0, 'y': 1}, {'a': 0, 'x': 4, 'z': 3, 'y': 1}, {'a': 1, 'x': 4, 'z': 0, 'y': 3}, {'a': 0, 'x': 4, 'z': 1, 'y': 3}, {'a': 2, 'x': 5, 'z': 1, 'y': 0}, {'a': 1, 'x': 5, 'z': 2, 'y': 0}, {'a': 2, 'x': 5, 'z': 0, 'y': 1}, {'a': 0, 'x': 5, 'z': 2, 'y': 1}, {'a': 1, 'x': 5, 'z': 0, 'y': 2}, {'a': 0, 'x': 5, 'z': 1, 'y': 2}]

答案 1 :(得分:1)

这是一个不依赖于itertools的解决方案,因为它会受到所有限制(一种产品产生独特结果且每种产品至少出现一次)的设计:

products = {'x','y','z','a'}
machine_capacity=8

def genCap(capacity = machine_capacity,used = 0):
    if used == len(products)-1: yield capacity,None
    else:
        for i in range(1,2+capacity-len(products)+used):
            yield i,genCap(capacity-i,used+1)
def printCaps(caps,current = []):
    if caps is None:
        print(dict(zip(products,current)))
        return
    for i in caps:
        printCaps(i[1],current+[i[0]])

printCaps(genCap())

可以通过尾递归等进行优化。看起来几乎像groupby,但我看不到使用它的简单方法。

对于后代我留下了旧的解决方案 - 产品重复计数,因此过滤它会成为它自己的问题:

你把产品与排列混淆了。以下是使用itertools产品的快速解决方案,以及Counter集合来创建所需的输出:

from collections import Counter
from itertools   import product

products = {'x','y','z','a'}
machine_capacity=8
for x in filter(lambda x: len(x) == len(products),
                map(Counter,product(products,repeat=machine_capacity))): 
    print(dict(x))

请注意,productmap都是懒惰的,因此在您需要之前不会对其进行评估。 Counter提供您想要的输出,并转换为dict进行清理。注意在任何地方都不保证订单。 filter用于确保您的所有产品至少出现一次(计数器的长度等于产品的长度) - 并且它也是惰性的,因此仅在您需要时进行评估。