python - 按类别创建项目列表的受限排列

标签 python set combinatorics

我正在尝试创建一系列项目列表的限制排列。每个项目都有一个类别,我需要找到项目组合,以使每个组合不包含来自同一类别的多个项目。为了说明,这里有一些示例数据:

   Name      | Category
   ==========|==========
1. Orange    | fruit
2. Apple     | fruit
3. GI-Joe    | toy
4. VCR       | electronics
5. Racquet   | sporting goods

组合将被限制为三个长度,我不需要每个长度的每个组合。因此,上述列表的一组组合可能是:

(Orange, GI-Joe, VCR)
(Orange, GI-Joe, Racquet)
(Orange, VCR, Racquet)
(Apple,  GI-Joe, VCR)
(Apple,  GI-Joe, Racquet)
... and so on.

我经常在各种列表上这样做。列表的长度永远不会超过 40 个项目,但可以理解的是,这可能会产生数千种组合(尽管每个列表可能会有大约 10 个独特的类别,这在一定程度上有所限制)

我想出了一些伪 python 来说明如何递归地实现它。自从我学习组合学以来已经太久了,但据我所知,这本质上是集合组合的子集,类似于 C(列表长度,所需大小)。可能有一些库模块可以使它更清洁(或至少更高效)

我想知道是否有比我现有的方法更好的方法(也许以某种方式使用 itertools.combinations):

# For the sake of this problem, let's assume the items are hashable so they
# can be added to a set.

def combinate(items, size=3):
    assert size >=2, "You jerk, don't try it."
    def _combinate(index, candidate):
        if len(candidate) == size:
            results.add(candidate)
            return
        candidate_cats = set(x.category for x in candidate)
        for i in range(index, len(items)):
            item = items[i]
            if item.category not in candidate_cats:
                _combinate(i, candidate + (item, ))

    results = set()
    for i, item in enumerate(items[:(1-size)]):
        _combinate(i, (item, ))

    return results

最佳答案

朴素的方法:

#!/usr/bin/env python

import itertools

items = {
    'fruits' : ('Orange', 'Apple'),
    'toys' : ('GI-Joe', ),
    'electronics' : ('VCR', ),
    'sporting_goods' : ('Racquet', )
}

def combinate(items, size=3):
    if size > len(items):
        raise Exception("Lower the `size` or add more products, dude!")

    for cats in itertools.combinations(items.keys(), size):
        cat_items = [[products for products in items[cat]] for cat in cats]
        for x in itertools.product(*cat_items):
            yield zip(cats, x)

if __name__ == '__main__':
    for x in combinate(items):
        print x

将产生:

# ==> 
#
# [('electronics', 'VCR'), ('toys', 'GI-Joe'), ('sporting_goods', 'Racquet')]
# [('electronics', 'VCR'), ('toys', 'GI-Joe'), ('fruits', 'Orange')]
# [('electronics', 'VCR'), ('toys', 'GI-Joe'), ('fruits', 'Apple')]
# [('electronics', 'VCR'), ('sporting_goods', 'Racquet'), ('fruits', 'Orange')]
# [('electronics', 'VCR'), ('sporting_goods', 'Racquet'), ('fruits', 'Apple')]
# [('toys', 'GI-Joe'), ('sporting_goods', 'Racquet'), ('fruits', 'Orange')]
# [('toys', 'GI-Joe'), ('sporting_goods', 'Racquet'), ('fruits', 'Apple')]

关于python - 按类别创建项目列表的受限排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3686521/

相关文章:

python - 使用 Python 检查电子邮件

c++ - 使用 std::set 的 .begin() 和 .end() 函数会产生意想不到的结果

python - 集合理解不适用于 Pydev (Python)

c - 高效计算 nCk mod p

二进制组合计数

python - 许多for在python生成器中的一行中

python - 求解分数时如何用模计算余数?

python - 如何从我的 Django 数据库中检索行数据作为列表?

python - python 中的成员资格测试比 set() 更快

python - N 选择列表的 N/2 个子列表