【问题标题】:2^n Itertools combinations with advanced filtering2^n 具有高级过滤功能的 Itertools 组合
【发布时间】:2016-03-24 23:26:24
【问题描述】:

我知道我可以使用 itertools 抽出组合,并定义组合组的大小,如下所示:

import itertools
print list(itertools.combinations(['V','M','T','O','Q','K','D','R'], 4))

这个输出就像一个元组列表,在这种情况下每个长度为 4。

从这里开始,我想做的是强制执行 2 个参数 - 1) 排除包含某些对的任何组合/元组 - 例如 V 和 M,或 Q 和 K。2) 强制每个元组仅包含1 封信实例。我相信 itertools 已经在做#2了。

应该保留的只是那些不包含任何这些预先确定的“假”对的元组组。因此,如果我排除包含 V 和 M 的组,则组 ('V','M','Q','D') 将无效,但 ('V','R','Q','D') 将有效。

对我来说最好的方法是什么?

【问题讨论】:

  • 您只需手动过滤栏即可滚动您自己的实现

标签: python set combinations permutation


【解决方案1】:

您可以定义一个验证函数并使用它进行过滤

>>> import itertools
>>> def is_valid(data):
        if 'V' in data and 'M' in data:
            return False
        if 'Q' in data and 'K' in data:
            return False
        return True

>>> filter(is_valid,itertools.combinations('VMTOQKDR', 4))
[('V', 'T', 'O', 'Q'), ('V', 'T', 'O', 'K'), ('V', 'T', 'O', 'D'), ('V', 'T', 'O', 'R'), ('V', 'T', 'Q', 'D'), ('V', 'T', 'Q', 'R'), ('V', 'T', 'K', 'D'), ('V', 'T', 'K', 'R'), ('V', 'T', 'D', 'R'), ('V', 'O', 'Q', 'D'), ('V', 'O', 'Q', 'R'), ('V', 'O', 'K', 'D'), ('V', 'O', 'K', 'R'), ('V', 'O', 'D', 'R'), ('V', 'Q', 'D', 'R'), ('V', 'K', 'D', 'R'), ('M', 'T', 'O', 'Q'), ('M', 'T', 'O', 'K'), ('M', 'T', 'O', 'D'), ('M', 'T', 'O', 'R'), ('M', 'T', 'Q', 'D'), ('M', 'T', 'Q', 'R'), ('M', 'T', 'K', 'D'), ('M', 'T', 'K', 'R'), ('M', 'T', 'D', 'R'), ('M', 'O', 'Q', 'D'), ('M', 'O', 'Q', 'R'), ('M', 'O', 'K', 'D'), ('M', 'O', 'K', 'R'), ('M', 'O', 'D', 'R'), ('M', 'Q', 'D', 'R'), ('M', 'K', 'D', 'R'), ('T', 'O', 'Q', 'D'), ('T', 'O', 'Q', 'R'), ('T', 'O', 'K', 'D'), ('T', 'O', 'K', 'R'), ('T', 'O', 'D', 'R'), ('T', 'Q', 'D', 'R'), ('T', 'K', 'D', 'R'), ('O', 'Q', 'D', 'R'), ('O', 'K', 'D', 'R')]
>>> 

编辑

为了使其更加灵活,您可以创建一个生成验证函数的函数,并将其与@PadraicCunningham 的使用集合的想法相结合

>>> import itertools
>>> def make_validator(*checks):
        checker=[set(x) for x in checks]
        def validator(data):
            return not any( st.issubset(data) for st in checker)
        return validator

>>> is_valid = make_validator("VM","QK")
>>> filter(is_valid, itertools.combinations('VMTOQKDR', 4))
[('V', 'T', 'O', 'Q'), ('V', 'T', 'O', 'K'), ('V', 'T', 'O', 'D'), ('V', 'T', 'O', 'R'), ('V', 'T', 'Q', 'D'), ('V', 'T', 'Q', 'R'), ('V', 'T', 'K', 'D'), ('V', 'T', 'K', 'R'), ('V', 'T', 'D', 'R'), ('V', 'O', 'Q', 'D'), ('V', 'O', 'Q', 'R'), ('V', 'O', 'K', 'D'), ('V', 'O', 'K', 'R'), ('V', 'O', 'D', 'R'), ('V', 'Q', 'D', 'R'), ('V', 'K', 'D', 'R'), ('M', 'T', 'O', 'Q'), ('M', 'T', 'O', 'K'), ('M', 'T', 'O', 'D'), ('M', 'T', 'O', 'R'), ('M', 'T', 'Q', 'D'), ('M', 'T', 'Q', 'R'), ('M', 'T', 'K', 'D'), ('M', 'T', 'K', 'R'), ('M', 'T', 'D', 'R'), ('M', 'O', 'Q', 'D'), ('M', 'O', 'Q', 'R'), ('M', 'O', 'K', 'D'), ('M', 'O', 'K', 'R'), ('M', 'O', 'D', 'R'), ('M', 'Q', 'D', 'R'), ('M', 'K', 'D', 'R'), ('T', 'O', 'Q', 'D'), ('T', 'O', 'Q', 'R'), ('T', 'O', 'K', 'D'), ('T', 'O', 'K', 'R'), ('T', 'O', 'D', 'R'), ('T', 'Q', 'D', 'R'), ('T', 'K', 'D', 'R'), ('O', 'Q', 'D', 'R'), ('O', 'K', 'D', 'R')]
>>> filter(make_validator("VM","QK",'MT',"DR"), itertools.combinations('VMTOQKDR', 4))
[('V', 'T', 'O', 'Q'), ('V', 'T', 'O', 'K'), ('V', 'T', 'O', 'D'), ('V', 'T', 'O', 'R'), ('V', 'T', 'Q', 'D'), ('V', 'T', 'Q', 'R'), ('V', 'T', 'K', 'D'), ('V', 'T', 'K', 'R'), ('V', 'O', 'Q', 'D'), ('V', 'O', 'Q', 'R'), ('V', 'O', 'K', 'D'), ('V', 'O', 'K', 'R'), ('M', 'O', 'Q', 'D'), ('M', 'O', 'Q', 'R'), ('M', 'O', 'K', 'D'), ('M', 'O', 'K', 'R'), ('T', 'O', 'Q', 'D'), ('T', 'O', 'Q', 'R'), ('T', 'O', 'K', 'D'), ('T', 'O', 'K', 'R')]
>>> 

make_validator 将您不想要的任意数量的排除组合作为参数,并创建一个执行检查并返回它的函数;您可以将结果保存在变量中或直接使用它

【讨论】:

  • 就灵活性和速度而言,这正是我所寻找的。在我看到这个之前,我不知道 itertools 也会拆分字符串。
  • string 就像一个字符列表,所以传递一个字符串或字符的文字列表对于任何使用 iterables 的函数都是一样的
  • 为了增加灵活性,您可以像我的新增功能一样创建一个验证器工厂
【解决方案2】:

我会用一组过滤:

import itertools
c = itertools.combinations(['V','M','T','O','Q','K','D','R'], 4)

st = {"V","M"}

print([co for co in c if not st.issubset(co)])

如果你想过滤两个:

st1 = {"V","M"}
st2 = {"Q","K"}

print([co for co in c if not st1.issubset(co) and not st2.issubset(co)])

如果您有两个以上,使用any 可能会更好:

sts = [{"V","M"},{"V","R"},{"T","O"}]

print([co for co in c if not any(st.issubset(co) for st in sts)])

如果你滚动你自己的组合逻辑,你不能避免创建所有的组合和过滤,即使你自己滚动在纯 python 中做它可能会更慢吧你有一个大数据集

【讨论】:

    【解决方案3】:

    您可以使用带有if 条件的列表推导:

    >>> [x for x in itertools.combinations('VMTOQKDR', 4) 
           if not (('V' in x and 'M' in x) or ('Q' in x and 'K' in x))]
    [('V', 'T', 'O', 'Q'),
     ('V', 'T', 'O', 'K'),
     ... 37 more ...
     ('O', 'Q', 'D', 'R'),
     ('O', 'K', 'D', 'R')]
    

    但是请注意,这仍然会遍历所有组合,并且只是“丢弃”无效的组合。例如,如果前两个元素是('V','M'),它将继续生成 `('V','M','O','R') 并将其丢弃,依此类推。对于在这种情况下生成的组合数量来说这不是问题。对于较大的组合,您可能希望使用自定义递归算法更早地丢弃无效的部分结果。

    【讨论】:

      猜你喜欢
      • 2021-05-23
      • 1970-01-01
      • 2013-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-18
      • 2012-06-09
      相关资源
      最近更新 更多