在某些情况下,我试图列举在计算四个玩家的Banzhaf power indices时可能发生的独特情况的数量,当没有*者并且有四个或五个获胜联盟时.
我使用以下代码生成一组我想要迭代的列表.
from itertools import chain, combinations
def powerset(iterable):
s = list(iterable)
return chain.from_iterable(map(list, combinations(s, r)) for r in range(2, len(s)+1))
def superpowerset(iterable):
s = powerset(iterable)
return chain.from_iterable(map(list, combinations(s, r)) for r in range(4, 6))
set_of_lists = superpowerset([1,2,3,4])
但是,如果在重映射中它们是等效的,则此集合中的两个列表不应被视为唯一.
使用以下列表作为示例:
[[1, 2], [1, 3], [2, 3], [1, 2, 4]]
如果每个元素2重命名为3,反之亦然,我们将获得:
[[1, 3], [1, 2], [3, 2], [1, 3, 4]]
每个子列表中的顺序并不重要,子列表的顺序也不重要.因此,交换列表可以重写为:
[[1, 2], [1, 3], [2, 3], [1, 3, 4]]
有4个值,因此可能发生P(4,4)= 24个可能的重映射(包括平凡映射).
有没有办法轻松检查?或者,更好的是,是否有办法避免生成这些列表?
我甚至不确定如何将第一个列表转换为第二个列表(但是可以从那里强制它).另外,我不限于数据类型(在某种程度上),使用freezeset也没关系.
编辑:tobias_k提供的解决方案回答了“检查”问题,但正如评论中所述,我认为我对这个问题采取了错误的方法.
解决方法:
这可能还没有完整的解决方案,但它可能会向您展示进一步调查的方向.
您可以将每个元素映射到有关“拓扑”的某些特征,以及它与其他元素的“连接”.你必须小心不要考虑集合中的顺序,或者 – 显然 – 元素本身.例如,您可以考虑元素出现的频率,它出现在哪个大小的组中,以及类似的东西.将这些指标与关键函数组合,按该键对元素进行排序,并按顺序为它们分配新名称.
def normalize(lists):
items = set(x for y in lists for x in y)
counter = itertools.count()
sorter = lambda x: sorted(len(y) for y in lists if x in y)
mapping = {k: next(counter) for k in sorted(items, key=sorter)}
return tuple(sorted(tuple(sorted(mapping[x] for x in y)) for y in lists))
这会将您的两个示例列表映射到相同的“规范化”列表:
>>> normalize([[1, 2], [1, 3], [2, 3], [1, 2, 4]])
((0, 1), (0, 2), (1, 2), (1, 2, 3))
>>> normalize([[1, 3], [1, 2], [3, 2], [1, 3, 4]])
((0, 1), (0, 2), (1, 2), (1, 2, 3))
当应用于所有列表时,它会将计数从330减少到36.我不知道这是否是最小的,但它看起来是一个好的开始.
>>> normalized = set(map(normalize, set_of_lists))
>>> len(normalized)
36