Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 创建序列列表,以便对每个不同的对进行多次计数_Python - Fatal编程技术网

Python 创建序列列表,以便对每个不同的对进行多次计数

Python 创建序列列表,以便对每个不同的对进行多次计数,python,Python,在创建序列列表的算法中出现了一些问题,这样每个不同的对都会重复计数,其中序列中的每个元素只能包含2个可能的其他元素中的1个 更清楚地说,如果我有语法,字母表是[A,B,C,D,E,F]: A->B,E B->C,D C->A,F D->F,B E->D,A F->E,C 表示我可以/应该拥有的唯一可能的对是[A、B、A、E、B、C、B、D、C、C、F、D、F、D、B、E、D、E、A、F、E、F、C] 例如,一个序列可能看起来像: A、 B,D,F,E,A,E,D,F,E,A,E A、 到目前为止

在创建序列列表的算法中出现了一些问题,这样每个不同的对都会重复计数,其中序列中的每个元素只能包含2个可能的其他元素中的1个

更清楚地说,如果我有语法,字母表是[A,B,C,D,E,F]:

A->B,E

B->C,D

C->A,F

D->F,B

E->D,A

F->E,C

表示我可以/应该拥有的唯一可能的对是[A、B、A、E、B、C、B、D、C、C、F、D、F、D、B、E、D、E、A、F、E、F、C]

例如,一个序列可能看起来像:

A、 B,D,F,E,A,E,D,F,E,A,E

A、 到目前为止,B,B,D,E,D都发生过一次,A,E,E,A,F,E,D,F不再可用,因为我们已经使用了两次。我们继续这种模式,直到没有更多可用的对为止。例如,上面序列中的下一个元素必须是D,因为我们已经用尽了选项E,A

从这一点出发,我可以得到所有序列,按照上面的语法,从A开始,长度不超过24,这样序列中的每一对都会重复两次

我最初的想法是创建一组节点,然后对其执行一个通用的DFS/BFS,以获取每个路径,同时计算我在树下看到的对数,当对太多时返回,当我达到24个深度时添加到路径列表中。有没有更好的方法来完成这件事?我觉得我想得太多了


注意:它也可以是一个可变深度,我可以从字母表中的任何元素开始。

这里有一个递归生成器,可以生成序列。这比我想象的还要容易:不需要回溯为了节省内存,我们使用一个dict计数来跟踪每对的计数。我们在递归调用之前增加计数,在递归调用之后重置计数

序列长度需要为25,才能在一个序列中获得12对中的每一对正好两次。以给定字母开头的序列总数为18954

grammar = {
    'A': 'BE',
    'B': 'CD',
    'C': 'AF',
    'D': 'BF',
    'E': 'AD',
    'F': 'CE',
}

pairs = [k + c for k, v in grammar.items() for c in v]
counts = dict.fromkeys(pairs, 0)

maxcount = 2
total_len = 25

def sequences(seq):
    if len(seq) == total_len:
        yield seq
        return

    k = seq[-1]
    for c in grammar[k]:
        pair = k + c
        if counts[pair] < maxcount:
            counts[pair] += 1
            yield from sequences(seq + c)
            counts[pair] -= 1

for i, seq in enumerate(sequences('A'), 1):
    print(i, seq)   
要在不打印所有序列的情况下快速计数序列,可以执行以下操作

print(sum(1 for _ in sequences('A')))
在运行Python 3.6.0的旧2GHz 32位机器上运行不到2秒钟


请注意,增加maxcount会显著增加序列的数量。例如,对于total_len=19,maxcount=2,序列总数为20622,对于total_len=19,maxcount=3,序列总数为169192。

这是一个递归生成器,用于生成序列。这比我想象的还要容易:不需要回溯为了节省内存,我们使用一个dict计数来跟踪每对的计数。我们在递归调用之前增加计数,在递归调用之后重置计数

序列长度需要为25,才能在一个序列中获得12对中的每一对正好两次。以给定字母开头的序列总数为18954

grammar = {
    'A': 'BE',
    'B': 'CD',
    'C': 'AF',
    'D': 'BF',
    'E': 'AD',
    'F': 'CE',
}

pairs = [k + c for k, v in grammar.items() for c in v]
counts = dict.fromkeys(pairs, 0)

maxcount = 2
total_len = 25

def sequences(seq):
    if len(seq) == total_len:
        yield seq
        return

    k = seq[-1]
    for c in grammar[k]:
        pair = k + c
        if counts[pair] < maxcount:
            counts[pair] += 1
            yield from sequences(seq + c)
            counts[pair] -= 1

for i, seq in enumerate(sequences('A'), 1):
    print(i, seq)   
要在不打印所有序列的情况下快速计数序列,可以执行以下操作

print(sum(1 for _ in sequences('A')))
在运行Python 3.6.0的旧2GHz 32位机器上运行不到2秒钟


请注意,增加maxcount会显著增加序列的数量。例如,对于total_len=19,maxcount=2,序列总数为20622,对于total_len=19,maxcount=3,序列总数为169192。

让我们从一个忽略最大计数=2限制的简单方法开始:

from pprint import pprint
from collections import defaultdict

def list_cycles(grammar, parent, length):
    if length == 1:
        return [parent]

    return [parent + x
        for node in grammar[parent]
        for x in list_cycles(grammar, node, length - 1)]

grammar = {
    'A': ['B', 'E'],
    'B': ['C', 'D'],
    'C': ['A', 'F'],
    'D': ['F', 'B'],
    'E': ['D', 'A'],
    'F': ['E', 'C'],
    }

cycles = list_cycles(grammar, 'A', 6)
print(f'{len(cycles)}\n')
pprint(cycles)
哪些产出:

32

['ABCABC',
 'ABCABD',
 'ABCAED',
 'ABCAEA',
 'ABCFED',
 'ABCFEA',
 'ABCFCA',
 'ABCFCF',
 'ABDFED',
 'ABDFEA',
 'ABDFCA',
 'ABDFCF',
 'ABDBCA',
 'ABDBCF',
 'ABDBDF',
 'ABDBDB',
 'AEDFED',
 'AEDFEA',
 'AEDFCA',
 'AEDFCF',
 'AEDBCA',
 'AEDBCF',
 'AEDBDF',
 'AEDBDB',
 'AEABCA',
 'AEABCF',
 'AEABDF',
 'AEABDB',
 'AEAEDF',
 'AEAEDB',
 'AEAEAB',
 'AEAEAE']
31

['ABCABC',
 'ABCABD',
 'ABCAED',
 'ABCAEA',
 'ABCFED',
 'ABCFEA',
 'ABCFCA',
 'ABCFCF',
 'ABDFED',
 'ABDFEA',
 'ABDFCA',
 'ABDFCF',
 'ABDBCA',
 'ABDBCF',
 'ABDBDF',
 'ABDBDB',
 'AEDFED',
 'AEDFEA',
 'AEDFCA',
 'AEDFCF',
 'AEDBCA',
 'AEDBCF',
 'AEDBDF',
 'AEDBDB',
 'AEABCA',
 'AEABCF',
 'AEABDF',
 'AEABDB',
 'AEAEDF',
 'AEAEDB',
 'AEAEAB']
我们的要求要求我们去掉像“AEAE”这样的条目。因此,让我们编写一个简单的类似DFS的实现:

from pprint import pprint
from collections import defaultdict

def adjusted_counts(counts, item):
    counts = counts.copy()
    counts[item] += 1
    return counts

def list_cycles(grammar, max_count, parent, length, counts):
    if length == 1:
        return [parent]

    return [parent + x
        for node in grammar[parent]
        for x in list_cycles(grammar, max_count, node, length - 1,
            adjusted_counts(counts, parent + node))
        if counts[parent + node] < max_count]

grammar = {
    'A': ['B', 'E'],
    'B': ['C', 'D'],
    'C': ['A', 'F'],
    'D': ['F', 'B'],
    'E': ['D', 'A'],
    'F': ['E', 'C'],
    }

cycles = list_cycles(grammar, 2, 'A', 6, defaultdict(int))
print(f'{len(cycles)}\n')
pprint(cycles)
最后,运行:

cycles = list_cycles(grammar, 2, 'A', 24, defaultdict(int))
print(len(cycles))
给出:

18954
结论性意见:

性能可能会通过@pm2ring版本的生成器得到改进 性能可能会通过一个更聪明的算法得到进一步提高,该算法只适用于这个特定的语法,max_count=2,length=24。我考虑的一个问题是:列举所有只使用一对的排列。然后,尝试在不同位置之间插入一次连接循环。
让我们从一个忽略max_count=2限制的简单方法开始:

from pprint import pprint
from collections import defaultdict

def list_cycles(grammar, parent, length):
    if length == 1:
        return [parent]

    return [parent + x
        for node in grammar[parent]
        for x in list_cycles(grammar, node, length - 1)]

grammar = {
    'A': ['B', 'E'],
    'B': ['C', 'D'],
    'C': ['A', 'F'],
    'D': ['F', 'B'],
    'E': ['D', 'A'],
    'F': ['E', 'C'],
    }

cycles = list_cycles(grammar, 'A', 6)
print(f'{len(cycles)}\n')
pprint(cycles)
哪些产出:

32

['ABCABC',
 'ABCABD',
 'ABCAED',
 'ABCAEA',
 'ABCFED',
 'ABCFEA',
 'ABCFCA',
 'ABCFCF',
 'ABDFED',
 'ABDFEA',
 'ABDFCA',
 'ABDFCF',
 'ABDBCA',
 'ABDBCF',
 'ABDBDF',
 'ABDBDB',
 'AEDFED',
 'AEDFEA',
 'AEDFCA',
 'AEDFCF',
 'AEDBCA',
 'AEDBCF',
 'AEDBDF',
 'AEDBDB',
 'AEABCA',
 'AEABCF',
 'AEABDF',
 'AEABDB',
 'AEAEDF',
 'AEAEDB',
 'AEAEAB',
 'AEAEAE']
31

['ABCABC',
 'ABCABD',
 'ABCAED',
 'ABCAEA',
 'ABCFED',
 'ABCFEA',
 'ABCFCA',
 'ABCFCF',
 'ABDFED',
 'ABDFEA',
 'ABDFCA',
 'ABDFCF',
 'ABDBCA',
 'ABDBCF',
 'ABDBDF',
 'ABDBDB',
 'AEDFED',
 'AEDFEA',
 'AEDFCA',
 'AEDFCF',
 'AEDBCA',
 'AEDBCF',
 'AEDBDF',
 'AEDBDB',
 'AEABCA',
 'AEABCF',
 'AEABDF',
 'AEABDB',
 'AEAEDF',
 'AEAEDB',
 'AEAEAB']
我们的要求要求我们去掉像“AEAE”这样的条目。因此,让我们编写一个简单的类似DFS的实现:

from pprint import pprint
from collections import defaultdict

def adjusted_counts(counts, item):
    counts = counts.copy()
    counts[item] += 1
    return counts

def list_cycles(grammar, max_count, parent, length, counts):
    if length == 1:
        return [parent]

    return [parent + x
        for node in grammar[parent]
        for x in list_cycles(grammar, max_count, node, length - 1,
            adjusted_counts(counts, parent + node))
        if counts[parent + node] < max_count]

grammar = {
    'A': ['B', 'E'],
    'B': ['C', 'D'],
    'C': ['A', 'F'],
    'D': ['F', 'B'],
    'E': ['D', 'A'],
    'F': ['E', 'C'],
    }

cycles = list_cycles(grammar, 2, 'A', 6, defaultdict(int))
print(f'{len(cycles)}\n')
pprint(cycles)
最后,运行:

cycles = list_cycles(grammar, 2, 'A', 24, defaultdict(int))
print(len(cycles))
给出:

18954
结论性意见:

性能可能会通过@pm2ring版本的生成器得到改进 性能可能会通过一个更聪明的算法得到进一步提高,该算法只适用于这个特定的语法,max_count=2,length=24。我考虑的一个问题是:列举所有只使用一对的排列。然后,尝试在不同位置之间插入一次连接循环。
在我们真的这么做之前,我们知道有多少可能性吗?它可能比你的记忆还大。。。否则,这可能只是一个递归问题,对于集合长度,您将
保存一个由12个元素组成的计数器列表,每使用一个序列,计数器列表将减少2个元素。如果你的可能性没有超出你的记忆,那么就可以很快地列出。我不认为你可以实现一个递归选项,因为可能性的数量可能是可变的,有人可能会要求一定的深度。为了解决这个问题,让我们假设序列长度为[0,48]。因为您指定我们需要每对序列重复两次,所以递归从那里开始。我的错误-我的意思是这对序列可以重复用户指定的次数,但我一直在尝试具体地解决,如果它只有两次,并从中归纳出我喜欢Rocky Li关于维护计数器的想法。您可以通过递归回溯来实现这一点。在每一步中,使用该语法,您最多有2个选择,因此从A开始的长度为24的序列数量只有2^23,大约800万;我假设限制一对可以使用的次数会大大减少这个数量。在我们真正这样做之前,我们知道有多少可能性吗?它可能比你的记忆还大。。。否则,这可能只是一个递归问题,对于set length,您将有一个计数器列表,其中包含12个元素,每个元素为2,每次使用序列时都会减少。如果你的可能性没有超出你的记忆,那么就可以很快地列出。我不认为你可以实现一个递归选项,因为可能性的数量可能是可变的,有人可能会要求一定的深度。为了解决这个问题,让我们假设序列长度为[0,48]。因为您指定我们需要每对序列重复两次,所以递归从那里开始。我的错误-我的意思是这对序列可以重复用户指定的次数,但我一直在尝试具体地解决,如果它只有两次,并从中归纳出我喜欢Rocky Li关于维护计数器的想法。您可以通过递归回溯来实现这一点。在每一步中,使用该语法,您最多有2个选择,因此从A开始的长度为24的序列数量只有2^23,大约800万;我假设限制一对的使用次数会大大减少这个数字;D@MateenUlhaq这让人放心我们得到了同样的数字,18954;D@MateenUlhaq这让人放心生成器肯定有助于完成此类任务,但不是因为它们的速度:生成器通常比基于列表的方法稍慢。它们最大的好处是内存占用更小。在您的版本中,一个主要的时间和RAM接收器是所有这些计数拷贝,它们需要时间来分配、填充和释放。例如,对于max_count=2,length=17,您的代码创建131070个计数以生成11933个序列。Python在使用内存方面非常有效:它管理自己的内存池,并在可能的情况下回收东西,但是创建一大堆对象会增加内存。嗯,是这样,但是它仍然比您的实现慢几十倍。我有一种感觉,它可能与列表连接的数量9704222有关。。。!以及它们的添加方向lfold vs rfold。此外,我没有使用list.append.Generators来完成这样的任务,但这并不是因为它们的速度:生成器通常比等效的基于列表的方法稍慢。它们最大的好处是内存占用更小。在您的版本中,一个主要的时间和RAM接收器是所有这些计数拷贝,它们需要时间来分配、填充和释放。例如,对于max_count=2,length=17,您的代码创建131070个计数以生成11933个序列。Python在使用内存方面非常有效:它管理自己的内存池,并在可能的情况下回收东西,但是创建一大堆对象会增加内存。嗯,是这样,但是它仍然比您的实现慢几十倍。我有一种感觉,它可能与列表连接的数量9704222有关。。。!以及它们的添加方向lfold vs rfold。此外,我没有使用list.append。