可迭代对象¶
- class sympy.utilities.iterables.NotIterable[源代码][源代码]¶
在创建一个类时使用此mixin,当在其实例上调用iterable()时,该类不应返回true,因为例如在实例上调用list()会导致无限循环。
- sympy.utilities.iterables.binary_partitions(n)[源代码][源代码]¶
生成 n 的二进制分区。
二进制分区仅由2的幂次方组成。每一步将 \(2^{k+1}\) 分解为 \(2^k\) 和 \(2^k\)。因此,16 被转换为 8 和 8。
参考文献
[1]TAOCP 4, 第 7.2.1.5 节, 问题 64
示例
>>> from sympy.utilities.iterables import binary_partitions >>> for i in binary_partitions(5): ... print(i) ... [4, 1] [2, 2, 1] [2, 1, 1, 1] [1, 1, 1, 1, 1]
- sympy.utilities.iterables.capture(func)[源代码][源代码]¶
返回 func() 的打印输出。
func
应该是一个不带参数的函数,该函数通过打印语句生成输出。>>> from sympy.utilities.iterables import capture >>> from sympy import pprint >>> from sympy.abc import x >>> def foo(): ... print('hello world!') ... >>> 'hello' in capture(foo) # foo, not foo() True >>> capture(lambda: pprint(2/x)) '2\n-\nx\n'
- sympy.utilities.iterables.common_prefix(*seqs)[源代码][源代码]¶
返回
seqs
中序列的共同起始子序列。>>> from sympy.utilities.iterables import common_prefix >>> common_prefix(list(range(3))) [0, 1, 2] >>> common_prefix(list(range(3)), list(range(4))) [0, 1, 2] >>> common_prefix([1, 2, 3], [1, 2, 5]) [1, 2] >>> common_prefix([1, 2, 3], [1, 3, 5]) [1]
- sympy.utilities.iterables.common_suffix(*seqs)[源代码][源代码]¶
返回
seqs
中序列的共同结尾子序列。>>> from sympy.utilities.iterables import common_suffix >>> common_suffix(list(range(3))) [0, 1, 2] >>> common_suffix(list(range(3)), list(range(4))) [] >>> common_suffix([1, 2, 3], [9, 2, 3]) [2, 3] >>> common_suffix([1, 2, 3], [9, 7, 3]) [3]
- sympy.utilities.iterables.connected_components(G)[源代码][源代码]¶
无向图的连通分量或有向图的弱连通分量。
- 参数:
- Gtuple[list, list[tuple[T, T]]]
一个由图的顶点列表和边列表组成的元组,其连通分量需要被找到。
注释
图的顶点必须对所使用的数据结构是可哈希的。如果顶点是不可哈希的,请将它们替换为整数索引。
此函数使用 Tarjan 算法在 `O(|V|+|E|)`(线性)时间内计算连通分量。
参考文献
示例
给定一个无向图:
graph { A -- B C -- D }
如果我们包含每个边的双向方向,可以使用此函数找到连通分量:
>>> from sympy.utilities.iterables import connected_components >>> V = ['A', 'B', 'C', 'D'] >>> E = [('A', 'B'), ('B', 'A'), ('C', 'D'), ('D', 'C')] >>> connected_components((V, E)) [['A', 'B'], ['C', 'D']]
有向图的弱连通分量可以以相同的方式找到。
- sympy.utilities.iterables.filter_symbols(iterator, exclude)[源代码][源代码]¶
仅从 \(iterator\) 中产生那些不在 \(exclude\) 中的元素。
- 参数:
- 迭代器可迭代对象
迭代器以获取元素
- 排除可迭代对象
要排除的元素
- 返回:
- 迭代器迭代器
过滤迭代器
- sympy.utilities.iterables.flatten(iterable, levels=None, cls=None)[源代码][源代码]¶
递归地解嵌套可迭代容器。
>>> from sympy import flatten
>>> flatten([1, 2, 3]) [1, 2, 3] >>> flatten([1, 2, [3]]) [1, 2, 3] >>> flatten([1, [2, 3], [4, 5]]) [1, 2, 3, 4, 5] >>> flatten([1.0, 2, (1, None)]) [1.0, 2, 1, None]
如果你想只解嵌套指定层数的嵌套容器,那么将
levels
标志设置为所需的层数:>>> ls = [[(-2, -1), (1, 2)], [(0, 0)]]
>>> flatten(ls, levels=1) [(-2, -1), (1, 2), (0, 0)]
如果指定了 cls 参数,它将仅展平该类的实例,例如:
>>> from sympy import Basic, S >>> class MyOp(Basic): ... pass ... >>> flatten([MyOp(S(1), MyOp(S(2), S(3)))], cls=MyOp) [1, 2, 3]
改编自 https://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks
- sympy.utilities.iterables.generate_bell(n)[源代码][源代码]¶
返回 [0, 1, …, n - 1] 的所有排列,使得每个排列与上一个排列仅通过交换一对相邻元素而不同。
n!
个排列以迭代器的形式返回。为了从一个随机的起始排列中获取下一个排列,使用 Permutation 类的next_trotterjohnson
方法(该方法以不同的方式生成相同的序列)。参考文献
[5]通过 ECO 生成对合、错排及其相关结构 Vincent Vajnovszki, DMTCS 第1卷第12期, 2010
示例
>>> from itertools import permutations >>> from sympy.utilities.iterables import generate_bell >>> from sympy import zeros, Matrix
这是在敲响实体钟时使用的排列方式,并且不会产生按字典顺序排列的排列。相反,这些排列彼此之间恰好相差一个逆序,并且交换发生的位置以一种简单的方式周期性变化。考虑由
permutations
和generate_bell
生成的4个元素的前几个排列:>>> list(permutations(range(4)))[:5] [(0, 1, 2, 3), (0, 1, 3, 2), (0, 2, 1, 3), (0, 2, 3, 1), (0, 3, 1, 2)] >>> list(generate_bell(4))[:5] [(0, 1, 2, 3), (0, 1, 3, 2), (0, 3, 1, 2), (3, 0, 1, 2), (3, 0, 2, 1)]
注意,第2和第3个字典序排列有3个元素错位,而每个“钟”排列相对于前一个排列总是只有两个元素错位(因此排列的符号(+/-1)与前一个排列的符号相反)。
通过追踪最大数在排列中的位置,可以看到反转位置在各元素间的变化情况:
>>> m = zeros(4, 24) >>> for i, p in enumerate(generate_bell(4)): ... m[:, i] = Matrix([j - 3 for j in list(p)]) # make largest zero >>> m.print_nonzero('X') [XXX XXXXXX XXXXXX XXX] [XX XX XXXX XX XXXX XX XX] [X XXXX XX XXXX XX XXXX X] [ XXXXXX XXXXXX XXXXXX ]
- sympy.utilities.iterables.generate_derangements(s)[源代码][源代码]¶
返回可迭代对象
s
元素的唯一错位排列。示例
>>> from sympy.utilities.iterables import generate_derangements >>> list(generate_derangements([0, 1, 2])) [[1, 2, 0], [2, 0, 1]] >>> list(generate_derangements([0, 1, 2, 2])) [[2, 2, 0, 1], [2, 2, 1, 0]] >>> list(generate_derangements([0, 1, 1])) []
- sympy.utilities.iterables.generate_involutions(n)[源代码][源代码]¶
生成对合。
一个对合是一个置换,当它与自身相乘时等于单位置换。在这个实现中,对合是使用固定点生成的。
另外,一个对合可以被视为一个不包含任何长度大于二的循环的排列。
参考文献
示例
>>> from sympy.utilities.iterables import generate_involutions >>> list(generate_involutions(3)) [(0, 1, 2), (0, 2, 1), (1, 0, 2), (2, 1, 0)] >>> len(list(generate_involutions(4))) 10
- sympy.utilities.iterables.generate_oriented_forest(n)[源代码][源代码]¶
该算法生成有向森林。
有向图是一种没有对称有向边的有向图。森林是一个无环图,即它没有环。森林也可以描述为树的不相交并集,树是任意两个顶点通过恰好一条简单路径连接的图。
参考文献
[1]T. Beyer and S.M. Hedetniemi: constant time generation of rooted trees, SIAM J. Computing Vol. 9, No. 4, November 1980
示例
>>> from sympy.utilities.iterables import generate_oriented_forest >>> list(generate_oriented_forest(4)) [[0, 1, 2, 3], [0, 1, 2, 2], [0, 1, 2, 1], [0, 1, 2, 0], [0, 1, 1, 1], [0, 1, 1, 0], [0, 1, 0, 1], [0, 1, 0, 0], [0, 0, 0, 0]]
- sympy.utilities.iterables.group(seq, multiple=True)[源代码][源代码]¶
将一个序列分割成包含相等、相邻元素的列表的列表。
参见
示例
>>> from sympy import group
>>> group([1, 1, 1, 2, 2, 3]) [[1, 1, 1], [2, 2], [3]] >>> group([1, 1, 1, 2, 2, 3], multiple=False) [(1, 3), (2, 2), (3, 1)] >>> group([1, 1, 3, 2, 2, 1], multiple=False) [(1, 2), (3, 1), (2, 2), (1, 1)]
- sympy.utilities.iterables.has_dups(seq)[源代码][源代码]¶
如果
seq
中有任何重复元素,则返回 True。示例
>>> from sympy import has_dups, Dict, Set >>> has_dups((1, 2, 1)) True >>> has_dups(range(3)) False >>> all(has_dups(c) is False for c in (set(), Set(), dict(), Dict())) True
- sympy.utilities.iterables.has_variety(seq)[源代码][源代码]¶
如果
seq
中有任何不同的元素,则返回 True。示例
>>> from sympy import has_variety
>>> has_variety((1, 2, 1)) True >>> has_variety((1, 1, 1)) False
- sympy.utilities.iterables.ibin(n, bits=None, str=False)[源代码][源代码]¶
返回一个长度为
bits
的列表,对应于n
的二进制值,其中较小的位在右边(最后)。如果省略了 bits,长度将是表示n
所需的数量。如果希望位以相反的顺序排列,请使用返回列表的[::-1]
切片。如果需要从
[0, 0,..., 0]
到[1, 1, ..., 1]
的所有比特长度列表的序列,请为 bits 传递一个非整数,例如'all'
。如果需要位 字符串,请传递
str=True
。示例
>>> from sympy.utilities.iterables import ibin >>> ibin(2) [1, 0] >>> ibin(2, 4) [0, 0, 1, 0]
如果所有对应于 0 到 2**n - 1 的列表,传递一个非整数的位数:
>>> bits = 2 >>> for i in ibin(2, 'all'): ... print(i) (0, 0) (0, 1) (1, 0) (1, 1)
如果需要一个给定长度的比特字符串,请使用 str=True:
>>> n = 123 >>> bits = 10 >>> ibin(n, bits, str=True) '0001111011' >>> ibin(n, bits, str=True)[::-1] # small bits left '1101111000' >>> list(ibin(3, 'all', str=True)) ['000', '001', '010', '011', '100', '101', '110', '111']
- sympy.utilities.iterables.iproduct(*iterables)[源代码][源代码]¶
可迭代对象的笛卡尔积。
可迭代对象的笛卡尔积生成器。这与 itertools.product 类似,但它适用于无限可迭代对象,并最终会生成无限积中的任何项。
示例
>>> from sympy.utilities.iterables import iproduct >>> sorted(iproduct([1,2], [3,4])) [(1, 3), (1, 4), (2, 3), (2, 4)]
使用无限迭代器:
>>> from sympy import S >>> (3,) in iproduct(S.Integers) True >>> (3, 4) in iproduct(S.Integers, S.Integers) True
参见
itertools.product 的中文翻译
- sympy.utilities.iterables.is_palindromic(s, i=0, j=None)[源代码][源代码]¶
如果序列在整个序列(默认)或Python切片
s[i: j]
中从左到右与从右到左相同,则返回 True;否则返回 False。示例
>>> from sympy.utilities.iterables import is_palindromic >>> is_palindromic([1, 0, 1]) True >>> is_palindromic('abcbb') False >>> is_palindromic('abcbb', 1) False
正常的Python切片是在原地进行的,因此不需要为测试创建序列的切片:
>>> is_palindromic('abcbb', 1, -1) True >>> is_palindromic('abcbb', -4, -1) True
- sympy.utilities.iterables.is_sequence(i, include=None)[源代码][源代码]¶
返回一个布尔值,指示
i
是否是 SymPy 意义上的序列。如果任何未通过以下测试的对象应被视为您的应用程序中的序列,请将 ‘include’ 设置为该对象的类型;多个类型应以元组的形式传递。注意:虽然生成器可以生成一个序列,但它们通常需要特殊处理以确保在生成器耗尽之前捕获其元素,因此这些元素默认不包含在序列的定义中。
另见:可迭代对象
示例
>>> from sympy.utilities.iterables import is_sequence >>> from types import GeneratorType >>> is_sequence([]) True >>> is_sequence(set()) False >>> is_sequence('abc') False >>> is_sequence('abc', include=str) True >>> generator = (c for c in 'abc') >>> is_sequence(generator) False >>> is_sequence(generator, include=(str, GeneratorType)) True
- sympy.utilities.iterables.iterable(
- i,
- exclude=(<class 'str'>,
- <class 'dict'>,
- <class 'sympy.utilities.iterables.NotIterable'>),
返回一个布尔值,指示
i
是否为 SymPy 可迭代对象。True 还表示迭代器是有限的,例如,您可以在实例上调用 list(…)。当 SymPy 处理可迭代对象时,它几乎总是假设该可迭代对象不是字符串或映射,因此这些默认情况下会被排除。如果你想使用纯 Python 定义,请设置 exclude=None。要排除多个项目,请将它们作为元组传递。
你也可以在你的类上将 _iterable 属性设置为 True 或 False,这将覆盖这里的检查,包括排除测试。
通常来说,一些 SymPy 函数使用这个来检查它们是否应该递归地映射到一个对象上。如果一个对象在 Python 意义上是可迭代的,但不希望这种行为(例如,因为它的迭代不是有限的,或者因为迭代可能会引发不想要的计算),它应该通过将 _iterable 属性设置为 False 来禁用它。
另请参阅:is_sequence
示例
>>> from sympy.utilities.iterables import iterable >>> from sympy import Tuple >>> things = [[1], (1,), set([1]), Tuple(1), (j for j in [1, 2]), {1:2}, '1', 1] >>> for i in things: ... print('%s %s' % (iterable(i), type(i))) True <... 'list'> True <... 'tuple'> True <... 'set'> True <class 'sympy.core.containers.Tuple'> True <... 'generator'> False <... 'dict'> False <... 'str'> False <... 'int'>
>>> iterable({}, exclude=None) True >>> iterable({}, exclude=str) True >>> iterable("no", exclude=str) False
- sympy.utilities.iterables.kbins(l, k, ordered=None)[源代码][源代码]¶
返回序列
l
被划分为k
个分区。示例
默认情况下,项目按相同顺序排列,但分组为 k 个分区而不进行任何重新排序:
>>> from sympy.utilities.iterables import kbins >>> for p in kbins(list(range(5)), 2): ... print(p) ... [[0], [1, 2, 3, 4]] [[0, 1], [2, 3, 4]] [[0, 1, 2], [3, 4]] [[0, 1, 2, 3], [4]]
ordered
标志要么是 None(以给出元素的简单分区),要么是一个两位整数,表示分区的顺序和分区中项目的顺序是否重要。给定:A = [[0], [1, 2]] B = [[1, 2], [0]] C = [[2, 1], [0]] D = [[0], [2, 1]]
以下
ordered
的值具有所示的含义:00 means A == B == C == D 01 means A == B 10 means A == D 11 means A == A
>>> for ordered_flag in [None, 0, 1, 10, 11]: ... print('ordered = %s' % ordered_flag) ... for p in kbins(list(range(3)), 2, ordered=ordered_flag): ... print(' %s' % p) ... ordered = None [[0], [1, 2]] [[0, 1], [2]] ordered = 0 [[0, 1], [2]] [[0, 2], [1]] [[0], [1, 2]] ordered = 1 [[0], [1, 2]] [[0], [2, 1]] [[1], [0, 2]] [[1], [2, 0]] [[2], [0, 1]] [[2], [1, 0]] ordered = 10 [[0, 1], [2]] [[2], [0, 1]] [[0, 2], [1]] [[1], [0, 2]] [[0], [1, 2]] [[1, 2], [0]] ordered = 11 [[0], [1, 2]] [[0, 1], [2]] [[0], [2, 1]] [[0, 2], [1]] [[1], [0, 2]] [[1, 0], [2]] [[1], [2, 0]] [[1, 2], [0]] [[2], [0, 1]] [[2, 0], [1]] [[2], [1, 0]] [[2, 1], [0]]
- sympy.utilities.iterables.least_rotation(x, key=None)[源代码][源代码]¶
返回左旋所需的最小步数,以获得字典序最小的字符串/列表/元组等。
参考文献
[1]https://en.wikipedia.org/wiki/字典序最小字符串旋转
示例
>>> from sympy.utilities.iterables import least_rotation, rotate_left >>> a = [3, 1, 5, 1, 2] >>> least_rotation(a) 3 >>> rotate_left(a, _) [1, 2, 3, 1, 5]
- sympy.utilities.iterables.minlex(seq, directed=True, key=None)[源代码][源代码]¶
返回序列的旋转,其中词法上最小的元素首先出现,例如 \(cba ightarrow acb\)。
返回的序列是一个元组,除非输入序列是字符串,在这种情况下返回的是字符串。
如果
directed
为 False,则返回序列和反转序列中较小的那个,例如 \(cba ightarrow abc\)。如果
key
不是 None,那么它用于从可迭代对象中的每个元素提取比较键。示例
>>> from sympy.combinatorics.polyhedron import minlex >>> minlex((1, 2, 0)) (0, 1, 2) >>> minlex((1, 0, 2)) (0, 2, 1) >>> minlex((1, 0, 2), directed=False) (0, 1, 2)
>>> minlex('11010011000', directed=True) '00011010011' >>> minlex('11010011000', directed=False) '00011001011'
>>> minlex(('bb', 'aaa', 'c', 'a')) ('a', 'bb', 'aaa', 'c') >>> minlex(('bb', 'aaa', 'c', 'a'), key=len) ('c', 'a', 'bb', 'aaa')
- sympy.utilities.iterables.multiset(seq)[源代码][源代码]¶
返回多重集中可哈希序列的形式,其中值为序列中项目的多重性。
参见
示例
>>> from sympy.utilities.iterables import multiset >>> multiset('mississippi') {'i': 4, 'm': 1, 'p': 2, 's': 4}
- sympy.utilities.iterables.multiset_combinations(m, n, g=None)[源代码][源代码]¶
从多重集
m
中返回大小为n
的唯一组合。示例
>>> from sympy.utilities.iterables import multiset_combinations >>> from itertools import combinations >>> [''.join(i) for i in multiset_combinations('baby', 3)] ['abb', 'aby', 'bby']
>>> def count(f, s): return len(list(f(s, 3)))
组合的数量取决于字母的数量;唯一组合的数量取决于字母的重复方式。
>>> s1 = 'abracadabra' >>> s2 = 'banana tree' >>> count(combinations, s1), count(multiset_combinations, s1) (165, 23) >>> count(combinations, s2), count(multiset_combinations, s2) (165, 54)
- sympy.utilities.iterables.multiset_derangements(s)[源代码][源代码]¶
就地生成 s 元素的错位排列。
示例
>>> from sympy.utilities.iterables import multiset_derangements, uniq
因为多重集(非集合)的错位是在原地生成的,如果需要一个错位集合,则必须复制返回值,否则所有值都将相同:
>>> list(uniq([i for i in multiset_derangements('1233')])) [[None, None, None, None]] >>> [i.copy() for i in multiset_derangements('1233')] [['3', '3', '1', '2'], ['3', '3', '2', '1']] >>> [''.join(i) for i in multiset_derangements('1233')] ['3312', '3321']
- sympy.utilities.iterables.multiset_partitions(multiset, m=None)[源代码][源代码]¶
返回给定多重集(以列表形式)的唯一分区。如果
m
为 None,将返回所有多重集,否则只返回包含m
部分的分区。如果
multiset
是一个整数,将会提供一个范围 [0, 1, …, multiset - 1]。参见
注释
当多重集合中的所有元素相同时,返回的分区顺序由
partitions
例程决定。如果是在计算分区,那么使用nT
函数会更好。示例
>>> from sympy.utilities.iterables import multiset_partitions >>> list(multiset_partitions([1, 2, 3, 4], 2)) [[[1, 2, 3], [4]], [[1, 2, 4], [3]], [[1, 2], [3, 4]], [[1, 3, 4], [2]], [[1, 3], [2, 4]], [[1, 4], [2, 3]], [[1], [2, 3, 4]]] >>> list(multiset_partitions([1, 2, 3, 4], 1)) [[[1, 2, 3, 4]]]
只返回唯一的分区,并且这些分区将按规范顺序返回,无论输入顺序如何:
>>> a = [1, 2, 2, 1] >>> ans = list(multiset_partitions(a, 2)) >>> a.sort() >>> list(multiset_partitions(a, 2)) == ans True >>> a = range(3, 1, -1) >>> (list(multiset_partitions(a)) == ... list(multiset_partitions(sorted(a)))) True
如果省略 m,则将返回所有分区:
>>> list(multiset_partitions([1, 1, 2])) [[[1, 1, 2]], [[1, 1], [2]], [[1, 2], [1]], [[1], [1], [2]]] >>> list(multiset_partitions([1]*3)) [[[1, 1, 1]], [[1], [1, 1]], [[1], [1], [1]]]
- sympy.utilities.iterables.multiset_permutations(m, size=None, g=None)[源代码][源代码]¶
返回多重集
m
的唯一排列。示例
>>> from sympy.utilities.iterables import multiset_permutations >>> from sympy import factorial >>> [''.join(i) for i in multiset_permutations('aab')] ['aab', 'aba', 'baa'] >>> factorial(len('banana')) 720 >>> len(list(multiset_permutations('banana'))) 60
- sympy.utilities.iterables.necklaces(n, k, free=False)[源代码][源代码]¶
一个生成项链的例程,这些项链可以(free=True)或不可以(free=False)翻转以供查看。返回的“项链”由
n
个整数(珠子)组成,具有k
种不同的值(颜色)。只返回唯一的项链。参考文献
[2]Frank Ruskey, Carla Savage, 和 Terry Min Yih Wang, 生成项链, 算法杂志 13 (1992), 414-430; https://doi.org/10.1016/0196-6774(92)90047-G
示例
>>> from sympy.utilities.iterables import necklaces, bracelets >>> def show(s, i): ... return ''.join(s[j] for j in i)
“无限制项链”有时也被称为“手镯”(一个可以翻转的对象,一个可以反转的序列),而“项链”一词用于暗示一个不能反转的序列。因此,对于手镯来说,ACB == ABC(旋转和反转),而对于项链来说,这两个是不同的,因为仅旋转不能使这两个序列相同。
(助记符:手镯可以向后看,但项链不行。)
>>> B = [show('ABC', i) for i in bracelets(3, 3)] >>> N = [show('ABC', i) for i in necklaces(3, 3)] >>> set(N) - set(B) {'ACB'}
>>> list(necklaces(4, 2)) [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1)]
>>> [show('.o', i) for i in bracelets(4, 2)] ['....', '...o', '..oo', '.o.o', '.ooo', 'oooo']
- sympy.utilities.iterables.numbered_symbols(
- prefix='x',
- cls=None,
- start=0,
- exclude=(),
- *args,
- **assumptions,
生成一个由前缀和递增下标组成的无限符号流,前提是这些符号不在
exclude
中出现。- 参数:
- 前缀str, 可选
要使用的字首。默认情况下,此函数将生成形式为“x0”、“x1”等的符号。
- cls类, 可选
要使用的类。默认情况下,它使用
Symbol
,但你也可以使用Wild
或Dummy
。- 开始int, 可选
起始数字。默认情况下,它是 0。
- 排除列表, 元组, cls 的集合, 可选
要排除的符号。
- *args, **kwargs
额外的位置参数和关键字参数被传递给 cls 类。
- 返回:
- sym符号
下标符号。
- sympy.utilities.iterables.ordered_partitions(n, m=None, sort=True)[源代码][源代码]¶
生成整数 n 的有序分区。
- 参数:
- n整数
- mint, 可选
默认值给出所有大小的分区,否则只给出大小为 m 的分区。此外,如果 m 不是 None,则分区是 就地 生成的(参见示例)。
- 排序bool, 默认: True
控制当 m 不为 None 时,分区是否按排序顺序返回;当为 False 时,分区将尽可能快地返回,元素已排序,但当 m|n 时,分区将不会按升序字典顺序排列。
参考文献
[1]生成整数分区,[在线],可用:https://jeromekelleher.net/generating-integer-partitions.html
[2]Jerome Kelleher 和 Barry O’Sullivan, “生成所有分区:两种编码的比较”, [在线], 可获取: https://arxiv.org/pdf/0909.2331v2.pdf
示例
>>> from sympy.utilities.iterables import ordered_partitions
按字典序升序排列的5的所有分区:
>>> for p in ordered_partitions(5): ... print(p) [1, 1, 1, 1, 1] [1, 1, 1, 2] [1, 1, 3] [1, 2, 2] [1, 4] [2, 3] [5]
只有两个部分的5的分区:
>>> for p in ordered_partitions(5, 2): ... print(p) [1, 4] [2, 3]
当
m
被给出时,为了速度原因,给定的列表对象将被多次使用,因此你将不会看到正确的分区,除非你在每次生成时都复制一份:>>> [p for p in ordered_partitions(7, 3)] [[1, 1, 1], [1, 1, 1], [1, 1, 1], [2, 2, 2]] >>> [list(p) for p in ordered_partitions(7, 3)] [[1, 1, 5], [1, 2, 4], [1, 3, 3], [2, 2, 3]]
当
n
是m
的倍数时,元素仍然会被排序,但如果 sort 为 False,分区本身将是 无序的;默认情况下,它们会按字典顺序升序返回。>>> for p in ordered_partitions(6, 2): ... print(p) [1, 5] [2, 4] [3, 3]
但如果速度比排序更重要,可以将 sort 设置为 False:
>>> for p in ordered_partitions(6, 2, sort=False): ... print(p) [1, 5] [3, 3] [2, 4]
- sympy.utilities.iterables.partitions(n, m=None, k=None, size=False)[源代码][源代码]¶
生成正整数 n 的所有分区。
每个分区表示为一个字典,将一个整数映射到该整数在分区中的副本数。例如,返回的4的第一个分区是{4: 1},即“4: 一个”。
- 参数:
- n整数
- mint, 可选
限制分区中的部分数量(助记符:m,最大部分)
- kint, 可选
限制分区中保留的数字数量(助记符:k,键)
- 大小bool, 默认值: False
如果
True
,则返回 (M, P),其中 M 是重数的总和,P 是生成的分区。如果False
,则仅返回生成的分区。
参考文献
[1]从Tim Peter的版本修改以允许k和m值:https://code.activestate.com/recipes/218332-generator-for-integer-partitions/
示例
>>> from sympy.utilities.iterables import partitions
分区中出现的数字(返回字典的键)受限于 k:
>>> for p in partitions(6, k=2): ... print(p) {2: 3} {1: 2, 2: 2} {1: 4, 2: 1} {1: 6}
分区中部分的最大数量(返回字典中值的总和)受限于 m(默认值 None 表示分区从 1 到 n):
>>> for p in partitions(6, m=2): ... print(p) ... {6: 1} {1: 1, 5: 1} {2: 1, 4: 1} {3: 2}
- sympy.utilities.iterables.permute_signs(t)[源代码][源代码]¶
返回一个迭代器,其中 t 的非零元素的符号被置换。
示例
>>> from sympy.utilities.iterables import permute_signs >>> list(permute_signs((0, 1, 2))) [(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2)]
- sympy.utilities.iterables.postfixes(seq)[源代码][源代码]¶
生成序列的所有后缀。
示例
>>> from sympy.utilities.iterables import postfixes
>>> list(postfixes([1,2,3,4])) [[4], [3, 4], [2, 3, 4], [1, 2, 3, 4]]
- sympy.utilities.iterables.prefixes(seq)[源代码][源代码]¶
生成序列的所有前缀。
示例
>>> from sympy.utilities.iterables import prefixes
>>> list(prefixes([1,2,3,4])) [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
- sympy.utilities.iterables.random_derangement(t, choice=None, strict=True)[源代码][源代码]¶
返回一个元素列表,其中没有任何元素处于它们原来的位置。如果一个元素占据了超过一半的位置,则会引发错误,因为不可能进行重排。要尽可能多地重排项目——其中一些最常见的元素仍保留在它们原来的位置——请传递 \(strict=False\)。要生成一个伪随机重排,请传递一个伪随机选择器,如 `choice`(见下文)。
示例
>>> from sympy.utilities.iterables import random_derangement >>> t = 'SymPy: a CAS in pure Python' >>> d = random_derangement(t) >>> all(i != j for i, j in zip(d, t)) True
通过使用伪随机生成器进行选择,可以获得可预测的结果:
>>> from sympy.core.random import seed, choice as c >>> seed(1) >>> d = [''.join(random_derangement(t, c)) for i in range(5)] >>> assert len(set(d)) != 1 # we got different values
通过重新播种,可以获得相同的序列:
>>> seed(1) >>> d2 = [''.join(random_derangement(t, c)) for i in range(5)] >>> assert d == d2
- sympy.utilities.iterables.reshape(seq, how)[源代码][源代码]¶
根据
how
中的模板重塑序列。示例
>>> from sympy.utilities import reshape >>> seq = list(range(1, 9))
>>> reshape(seq, [4]) # lists of 4 [[1, 2, 3, 4], [5, 6, 7, 8]]
>>> reshape(seq, (4,)) # tuples of 4 [(1, 2, 3, 4), (5, 6, 7, 8)]
>>> reshape(seq, (2, 2)) # tuples of 4 [(1, 2, 3, 4), (5, 6, 7, 8)]
>>> reshape(seq, (2, [2])) # (i, i, [i, i]) [(1, 2, [3, 4]), (5, 6, [7, 8])]
>>> reshape(seq, ((2,), [2])) # etc.... [((1, 2), [3, 4]), ((5, 6), [7, 8])]
>>> reshape(seq, (1, [2], 1)) [(1, [2, 3], 4), (5, [6, 7], 8)]
>>> reshape(tuple(seq), ([[1], 1, (2,)],)) (([[1], 2, (3, 4)],), ([[5], 6, (7, 8)],))
>>> reshape(tuple(seq), ([1], 1, (2,))) (([1], 2, (3, 4)), ([5], 6, (7, 8)))
>>> reshape(list(range(12)), [2, [3], {2}, (1, (3,), 1)]) [[0, 1, [2, 3, 4], {5, 6}, (7, (8, 9, 10), 11)]]
- sympy.utilities.iterables.rotate_left(x, y)[源代码][源代码]¶
将列表 x 向左旋转 y 中指定的步数。
示例
>>> from sympy.utilities.iterables import rotate_left >>> a = [0, 1, 2] >>> rotate_left(a, 1) [1, 2, 0]
- sympy.utilities.iterables.rotate_right(x, y)[源代码][源代码]¶
将列表 x 向右旋转 y 中指定的步数。
示例
>>> from sympy.utilities.iterables import rotate_right >>> a = [0, 1, 2] >>> rotate_right(a, 1) [2, 0, 1]
- sympy.utilities.iterables.rotations(s, dir=1)[源代码][源代码]¶
返回一个生成器,生成 s 中的项目作为列表,其中每个后续列表的项目相对于前一个列表向左(默认)或向右(
dir=-1
)旋转。示例
>>> from sympy import rotations >>> list(rotations([1,2,3])) [[1, 2, 3], [2, 3, 1], [3, 1, 2]] >>> list(rotations([1,2,3], -1)) [[1, 2, 3], [3, 1, 2], [2, 3, 1]]
- sympy.utilities.iterables.roundrobin(*iterables)[源代码][源代码]¶
从 itertools 文档中提取的 roundrobin 配方:https://docs.python.org/3/library/itertools.html#itertools-recipes
roundrobin(‘ABC’, ‘D’, ‘EF’) –> A D E B F C
食谱归功于 George Sakkis
- sympy.utilities.iterables.runs(seq, op=<built-in function gt>)[源代码][源代码]¶
将序列分组为列表,其中连续元素在比较运算符
op
下都进行相同的比较:对于一个运行中的所有元素,op(seq[i + 1], seq[i]) 为 True。示例
>>> from sympy.utilities.iterables import runs >>> from operator import ge >>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2]) [[0, 1, 2], [2], [1, 4], [3], [2], [2]] >>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2], op=ge) [[0, 1, 2, 2], [1, 4], [3], [2, 2]]
- sympy.utilities.iterables.sequence_partitions(l, n, /)[源代码][源代码]¶
返回序列 \(l\) 被划分为 \(n\) 个区间的结果
- 参数:
- lSequence[T]
任意 Python 对象的非空序列
- n整数
一个正整数
- Yields:
- 出list[Sequence[T]]
一个包含连接操作的序列列表等于 \(l\)。这应符合 \(l\) 的类型。
注释
这是从 https://stackoverflow.com/questions/13131491/partition-n-items-into-k-bins-in-python-lazily 修改的 EnricoGiampieri 的分区生成器版本。
示例
>>> from sympy.utilities.iterables import sequence_partitions >>> for out in sequence_partitions([1, 2, 3, 4], 2): ... print(out) [[1], [2, 3, 4]] [[1, 2], [3, 4]] [[1, 2, 3], [4]]
- sympy.utilities.iterables.sequence_partitions_empty(l, n, /)[源代码][源代码]¶
返回将序列 \(l\) 划分为 \(n\) 个空序列的划分结果
- 参数:
- lSequence[T]
一个由任意Python对象组成的序列(可以是空的)
- n整数
一个正整数
- Yields:
- 出list[Sequence[T]]
一个包含连接操作的序列列表等于 \(l\)。这应符合 \(l\) 的类型。
示例
>>> from sympy.utilities.iterables import sequence_partitions_empty >>> for out in sequence_partitions_empty([1, 2, 3, 4], 2): ... print(out) [[], [1, 2, 3, 4]] [[1], [2, 3, 4]] [[1, 2], [3, 4]] [[1, 2, 3], [4]] [[1, 2, 3, 4], []]
- sympy.utilities.iterables.sift(seq, keyfunc, binary=False)[源代码][源代码]¶
根据
keyfunc
筛选序列seq
。- 返回:
- 当
binary
为False
(默认)时,输出是一个字典 seq
的元素存储在一个以值为键的列表中- 对于该元素的 keyfunc。如果
binary
为 True,则返回一个元组 - 返回包含列表
T
和F
,其中T
是一个列表 - 包含
keyfunc
为True
的 seq 元素 F
包含那些keyfunc
为False
的元素;- 如果
keyfunc
不是二进制的,则会引发 ValueError。
- 当
参见
ordered
示例
>>> from sympy.utilities import sift >>> from sympy.abc import x, y >>> from sympy import sqrt, exp, pi, Tuple
>>> sift(range(5), lambda x: x % 2) {0: [0, 2, 4], 1: [1, 3]}
sift() 返回一个 defaultdict() 对象,因此任何没有匹配的键都将返回 []。
>>> sift([x], lambda x: x.is_commutative) {True: [x]} >>> _[False] []
有时你不会知道你会得到多少个键:
>>> sift([sqrt(x), exp(x), (y**x)**2], ... lambda x: x.as_base_exp()[0]) {E: [exp(x)], x: [sqrt(x)], y: [y**(2*x)]}
有时你期望结果是二进制的;可以通过将
binary
设置为 True 来解包结果:>>> sift(range(4), lambda x: x % 2, binary=True) ([1, 3], [0, 2]) >>> sift(Tuple(1, pi), lambda x: x.is_rational, binary=True) ([1], [pi])
如果在使用筛选且预期结果为二进制的情况下,谓词实际上不是二进制的,则会引发 ValueError(这是一个很好的逻辑测试):
>>> unknown = exp(1) - pi # the rationality of this is unknown >>> args = Tuple(1, pi, unknown) >>> sift(args, lambda x: x.is_rational, binary=True) Traceback (most recent call last): ... ValueError: keyfunc gave non-binary output
非二进制筛选显示生成了3个密钥:
>>> set(sift(args, lambda x: x.is_rational).keys()) {None, False, True}
如果你需要对筛选后的项目进行排序,使用
ordered
可能会更好,它可以在排序时经济地对序列应用多个排序键。
- sympy.utilities.iterables.signed_permutations(t)[源代码][源代码]¶
返回一个迭代器,其中 t 的非零元素的符号和元素的顺序被置换,并且所有返回的值都是唯一的。
示例
>>> from sympy.utilities.iterables import signed_permutations >>> list(signed_permutations((0, 1, 2))) [(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2), (0, 2, 1), (0, -2, 1), (0, 2, -1), (0, -2, -1), (1, 0, 2), (-1, 0, 2), (1, 0, -2), (-1, 0, -2), (1, 2, 0), (-1, 2, 0), (1, -2, 0), (-1, -2, 0), (2, 0, 1), (-2, 0, 1), (2, 0, -1), (-2, 0, -1), (2, 1, 0), (-2, 1, 0), (2, -1, 0), (-2, -1, 0)]
- sympy.utilities.iterables.strongly_connected_components(G)[源代码][源代码]¶
有向图的强连通分量按逆拓扑顺序排列。
- 参数:
- Gtuple[list, list[tuple[T, T]]]
一个由图的顶点列表和边列表组成的元组,其强连通分量需要被找到。
注释
图的顶点必须对所使用的数据结构是可哈希的。如果顶点是不可哈希的,请将它们替换为整数索引。
此函数使用 Tarjan 算法来计算强连通分量,时间复杂度为 `O(|V|+|E|)`(线性时间)。
参考文献
[1]示例
考虑一个有向图(在dot表示法中):
digraph { A -> B A -> C B -> C C -> B B -> D }
其中顶点是字母 A、B、C 和 D。这个图可以使用 Python 的基本数据结构编码如下:
>>> V = ['A', 'B', 'C', 'D'] >>> E = [('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'B'), ('B', 'D')]
此图的强连通分量可以计算为
>>> from sympy.utilities.iterables import strongly_connected_components
>>> strongly_connected_components((V, E)) [['D'], ['B', 'C'], ['A']]
这也会以反向拓扑顺序给出组件。
由于包含 B 和 C 的子图存在循环,它们必须位于同一个强连通分量中。A 和 D 与图的其他部分相连,但不是以循环方式相连,因此它们各自形成独立的强连通分量。
- sympy.utilities.iterables.subsets(seq, k=None, repetition=False)[源代码][源代码]¶
生成一个 \(n\) 元素集合
seq
中的所有 \(k\) 子集(组合)。一个 \(n\) 元素集合的 \(k\) 子集是长度恰好为 \(k\) 的任何子集。\(n\) 元素集合的 \(k\) 子集的数量由
binomial(n, k)
给出,而总共有 \(2^n\) 个子集。如果 \(k\) 是None
,那么所有 \(2^n\) 个子集将从最短到最长返回。示例
>>> from sympy import subsets
subsets(seq, k)
将返回 \(\frac{n!}{k!(n - k)!}\) \(k\)-子集(组合),不重复,即一旦一个项目被移除,它就不能再被“取”:>>> list(subsets([1, 2], 2)) [(1, 2)] >>> list(subsets([1, 2])) [(), (1,), (2,), (1, 2)] >>> list(subsets([1, 2, 3], 2)) [(1, 2), (1, 3), (2, 3)]
subsets(seq, k, repetition=True)
将返回 \(\frac{(n - 1 + k)!}{k!(n - 1)!}\) 的组合 带 重复:>>> list(subsets([1, 2], 2, repetition=True)) [(1, 1), (1, 2), (2, 2)]
如果你请求的项目数量超过了集合中的数量,你会得到一个空集,除非你允许重复:
>>> list(subsets([0, 1], 3, repetition=False)) [] >>> list(subsets([0, 1], 3, repetition=True)) [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)]
- sympy.utilities.iterables.topological_sort(graph, key=None)[源代码][源代码]¶
图顶点的拓扑排序。
- 参数:
- 图tuple[list, list[tuple[T, T]]]
一个由图的顶点列表和边列表组成的元组,用于拓扑排序。
- 关键callable[T] (可选)
同一级别顶点的排序键。默认使用自然(例如字典序)排序(在这种情况下,基类型必须实现排序关系)。
参考文献
[1]示例
考虑一个图:
+---+ +---+ +---+ | 7 |\ | 5 | | 3 | +---+ \ +---+ +---+ | _\___/ ____ _/ | | / \___/ \ / | V V V V | +----+ +---+ | | 11 | | 8 | | +----+ +---+ | | | \____ ___/ _ | | \ \ / / \ | V \ V V / V V +---+ \ +---+ | +----+ | 2 | | | 9 | | | 10 | +---+ | +---+ | +----+ \________/
其中顶点是整数。这个图可以使用基本的Python数据结构编码如下:
>>> V = [2, 3, 5, 7, 8, 9, 10, 11] >>> E = [(7, 11), (7, 8), (5, 11), (3, 8), (3, 10), ... (11, 2), (11, 9), (11, 10), (8, 9)]
要为图
(V, E)
计算拓扑排序,请执行:>>> from sympy.utilities.iterables import topological_sort >>> topological_sort((V, E)) [3, 5, 7, 8, 11, 2, 9, 10]
如果需要特定的打破平局的方法,使用
key
参数:>>> topological_sort((V, E), key=lambda v: -v) [7, 5, 11, 3, 10, 8, 9, 2]
只有无环图才能被排序。如果输入的图有环,那么会引发
ValueError
>>> topological_sort((V, E + [(10, 7)])) Traceback (most recent call last): ... ValueError: cycle detected
- sympy.utilities.iterables.unflatten(iter, n=2)[源代码][源代码]¶
将
iter
分组为长度为n
的元组。如果iter
的长度不是n
的倍数,则引发错误。
- sympy.utilities.iterables.uniq(seq, result=None)[源代码][源代码]¶
从
seq
中生成唯一的元素作为迭代器。第二个参数result
用于内部使用;不需要为此传递任何内容。注意:如果在迭代过程中更改序列,如果已知序列的大小,将引发 RuntimeError;如果传递迭代器并推进迭代器,将更改此例程的输出,但不会有警告。
示例
>>> from sympy.utilities.iterables import uniq >>> dat = [1, 4, 1, 5, 4, 2, 1, 2] >>> type(uniq(dat)) in (list, tuple) False
>>> list(uniq(dat)) [1, 4, 5, 2] >>> list(uniq(x for x in dat)) [1, 4, 5, 2] >>> list(uniq([[1], [2, 1], [1]])) [[1], [2, 1]]
- sympy.utilities.iterables.variations(seq, n, repetition=False)[源代码][源代码]¶
返回一个迭代器,遍历
seq
的 n 大小变化(大小 N)。repetition
控制seq
中的项目是否可以出现多次;示例
variations(seq, n)
将返回 \(\frac{N!}{(N - n)!}\) 个seq
元素的无重复排列:>>> from sympy import variations >>> list(variations([1, 2], 2)) [(1, 2), (2, 1)]
variations(seq, n, True)
将返回通过允许元素重复得到的 \(N^n\) 排列:>>> list(variations([1, 2], 2, repetition=True)) [(1, 1), (1, 2), (2, 1), (2, 2)]
如果你请求的项目数量超过了集合中的数量,你会得到一个空集,除非你允许重复:
>>> list(variations([0, 1], 3, repetition=False)) [] >>> list(variations([0, 1], 3, repetition=True))[:4] [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]
变化¶
variations(seq, n) 返回列表中所有大小为 n 的变体。
有一个可选的第三个参数。必须是布尔值,如果设置为 True,则该方法返回包含重复的排列;如果设置为 False,则返回不包含重复的排列。
- 示例:
>>> from sympy.utilities.iterables import variations >>> list(variations([1,2,3], 2)) [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)] >>> list(variations([1,2,3], 2, True)) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
分区¶
尽管组合数学模块包含用于研究和操作分区的 Partition 和 IntegerPartition 类,但有一些函数可以生成分区,这些函数可以作为例程的低级工具使用:partitions
和 multiset_partitions
。前者给出整数分区,后者给出元素的枚举分区。还有一个例程 kbins
,它将给出分区的各种排列。为了以列表而不是字典的形式获取分区,有一个非常快的 ordered_partition
函数。最后,为了简单地获取分区数量的计数而不枚举它们,有一个 nT
函数。
另请参阅¶
sympy.utilities.iterables.ordered_partitions, sympy.functions.combinatorial.numbers.nT
partitions:
>>> from sympy.utilities.iterables import partitions
>>> [p.copy() for s, p in partitions(7, m=2, size=True) if s == 2]
[{1: 1, 6: 1}, {2: 1, 5: 1}, {3: 1, 4: 1}]
multiset_partitions:
>>> from sympy.utilities.iterables import multiset_partitions
>>> [p for p in multiset_partitions(3, 2)]
[[[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]]]
>>> [p for p in multiset_partitions([1, 1, 1, 2], 2)]
[[[1, 1, 1], [2]], [[1, 1, 2], [1]], [[1, 1], [1, 2]]]
kbins:
>>> from sympy.utilities.iterables import kbins
>>> def show(k):
... rv = []
... for p in k:
... rv.append(','.join([''.join(j) for j in p]))
... return sorted(rv)
...
>>> show(kbins("ABCD", 2))
['A,BCD', 'AB,CD', 'ABC,D']
>>> show(kbins("ABC", 2))
['A,BC', 'AB,C']
>>> show(kbins("ABC", 2, ordered=0)) # same as multiset_partitions
['A,BC', 'AB,C', 'AC,B']
>>> show(kbins("ABC", 2, ordered=1))
['A,BC', 'A,CB',
'B,AC', 'B,CA',
'C,AB', 'C,BA']
>>> show(kbins("ABC", 2, ordered=10))
['A,BC', 'AB,C', 'AC,B',
'B,AC', 'BC,A',
'C,AB']
>>> show(kbins("ABC", 2, ordered=11))
['A,BC', 'A,CB', 'AB,C', 'AC,B',
'B,AC', 'B,CA', 'BA,C', 'BC,A',
'C,AB', 'C,BA', 'CA,B', 'CB,A']