Python 计算唯一列表排列可能性



所以我在处理列表/字符串的排列时遇到了问题,我很难解决这个问题。

所以,假设我有几个列表:

list1 = ["a"]
list2 = ["a","b","c","d"]
list3 = ["b","e"]
list4 = ["f","g","a"]

我需要计算所有可能的排列组合的数量,同时从每个列表中选择 1 个字符。 所以,从第一个列表中,我选择一个角色。 "a",在这种情况下,因为列表中只有一个项目。 接下来,我从第二个列表中选择一个项目,但它不能是"a",因为它是我之前的列表中选择的,所以它可以是"b"、"c"或"d"。 接下来,我从第三个列表中选择一个项目,如果我在第一个列表中选择"a",在第二个列表中选择"b",我只能选择"e",因为之前已经使用了"b"。 第四个列表也是如此。

因此,我需要从列表中计算唯一字符组合的所有可能组合。 希望每个人都能理解我在这里问的问题。或者如果可能的话,我什至不需要创建排列列表,我只需要计算总共有多少种组合。 任何内存密集度较低的方法,因为实际问题中可能存在大量单独的列表

对我的问题更详细...如果我有两个列表:列表 1 = ["a"]列表2 = ["b"]

只有一个组合,因为您保留了排列字符串中的位置。 列表一不包含 b,因此唯一的组合可能是 ("a","b"),而不是 ("b","a")。 并进一步扩展这个问题的约束..我不一定想检索所有排列的结果,我只想返回可能的排列总数。 返回结果会占用太多内存,因为我将使用 15 个列表,每个列表中有 1 到 15 个字符。

使用 itertools.product 从列表中生成所有可能的组合。然后,使用 itertools.ifilter 过滤掉包含重复字符的所有组合。一种简单的方法是,如果您删除所有重复项(即,如果您从中创建集合),则检查列表的长度是否保持不变。

import itertools
list1 = ["a"]
list2 = ["a","b","c","d"]
list3 = ["b","e"]
list4 = ["f","g","a"]
f = lambda x: len(x) == len(set(x))
it = itertools.ifilter(f, itertools.product(list1, list2, list3, list4))
# print all combinations
for combination in it:
    print combination

使用 itertools.product。 它循环访问为每个列表选择一个项目的所有排列。 此外,使用列表推导来消除不符合要求的迭代。

>>> a='a'
>>> b='abcd'
>>> c='be'
>>> d='fga'
>>> import itertools
>>> [a+b+c+d for a,b,c,d in itertools.product(a,b,c,d) if b != a and c not in [a,b] and d not in [a,b,c]]
['abef', 'abeg', 'acbf', 'acbg', 'acef', 'aceg', 'adbf', 'adbg', 'adef', 'adeg']

您可以缓存"从第 i 个列表开始,不包括 S 中的元素"形式的计数。通过小心地将 S 限制为仅可以排除的字符(即,仅出现在后面的列表中)的元素,可以减少重复计算的数量。

下面是一个示例程序:

def count_uniq_combs(sets, i, excluding, cache):
    if i == len(sets): return 1
    key = (i, excluding)
    if key in cache:
        return cache[key]
    count = 0
    for c in sets[i][0]:
        if c in excluding: continue
        newx = (excluding | set([c])) & sets[i][1]
        count += count_uniq_combs(sets, i + 1, newx, cache)
    cache[key] = count
    print key, count
    return count
def count(xs):
    sets = [[set(x)] for x in xs]
    # Pre-compute the union of all subsequent sets.
    union = set()
    for s in reversed(sets):
        s.append(union)
        union = union | s[0]
    return count_uniq_combs(sets, 0, frozenset(), dict())
print count(['a', 'abcd', 'be', 'fga'])

它打印出实际计算的值(而不是从缓存中调用),如下所示:

(3, frozenset(['a'])) 2
(2, frozenset(['a'])) 4
(2, frozenset(['a', 'b'])) 2
(1, frozenset(['a'])) 10
(0, frozenset([])) 10

例如,在查看列表 2("b"、"e")时,只计算两个计数:一个排除了"a"和"b",另一个只排除了"a"。将此与朴素的实现进行比较,在朴素的实现中,您还需要计算许多其他组合(例如:"a"和"c")。

如果仍然不够快,您可以尝试启发式对列表进行排序:您希望稍后使用包含相对较少其他列表符号的列表。

最新更新