Iterables

partitions

Although the combinatorics module contains Partition and IntegerPartition classes for investigation and manipulation of partitions, there are a few functions to generate partitions that can be used as low-level tools for routines: partitions and multiset_partitions. The former gives integer partitions, and the latter gives enumerated partitions of elements.

partitions:

>>> from diofant.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 diofant.utilities.iterables import multiset_partitions
>>> list(multiset_partitions(3, 2))
[[[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]]]
>>> list(multiset_partitions([1, 1, 1, 2], 2))
[[[1, 1, 1], [2]], [[1, 1, 2], [1]], [[1, 1], [1, 2]]]

Docstring

class diofant.utilities.iterables.NotIterable[source]

Use this as mixin when creating a class which is not supposed to return true when is_iterable() is called on its instances. I.e. avoid infinite loop when calling e.g. list() on the instance

diofant.utilities.iterables.cantor_product(*args)[source]

Breadth-first (diagonal) cartesian product of iterables.

Each iterable is advanced in turn in a round-robin fashion. As usual with breadth-first, this comes at the cost of memory consumption.

>>> from itertools import count, islice
>>> list(islice(cantor_product(count(), count()), 9))
[(0, 0), (0, 1), (1, 0), (1, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)]
diofant.utilities.iterables.common_prefix(*seqs)[source]

Return the subsequence that is a common start of sequences in seqs.

>>> 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]
diofant.utilities.iterables.common_suffix(*seqs)[source]

Return the subsequence that is a common ending of sequences in seqs.

>>> 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]
diofant.utilities.iterables.default_sort_key(item, order=None)[source]

Return a key that can be used for sorting.

The key has the structure:

(class_key, (len(args), args), exponent.sort_key(), coefficient)

This key is supplied by the sort_key routine of Basic objects when item is a Basic object or an object (other than a string) that sympifies to a Basic object. Otherwise, this function produces the key.

The order argument is passed along to the sort_key routine and is used to determine how the terms within an expression are ordered. (See examples below) order options are: ‘lex’, ‘grlex’, ‘grevlex’, and reversed values of the same (e.g. ‘rev-lex’). The default order value is None (which translates to ‘lex’).

Examples

>>> from diofant.core.function import UndefinedFunction

The following are equivalent ways of getting the key for an object:

>>> x.sort_key() == default_sort_key(x)
True

Here are some examples of the key that is produced:

>>> default_sort_key(UndefinedFunction('f'))
((0, 0, 'UndefinedFunction'), (1, ('f',)), ((1, 0, 'Number'),
    (0, ()), (), 1), 1)
>>> default_sort_key('1')
((0, 0, 'str'), (1, ('1',)), ((1, 0, 'Number'), (0, ()), (), 1), 1)
>>> default_sort_key(Integer(1))
((1, 0, 'Number'), (0, ()), (), 1)
>>> default_sort_key(2)
((1, 0, 'Number'), (0, ()), (), 2)

While sort_key is a method only defined for Diofant objects, default_sort_key will accept anything as an argument so it is more robust as a sorting key. For the following, using key= lambda i: i.sort_key() would fail because 2 doesn’t have a sort_key method; that’s why default_sort_key is used. Note, that it also handles sympification of non-string items likes ints:

>>> a = [2, I, -I]
>>> sorted(a, key=default_sort_key)
[2, -I, I]

The returned key can be used anywhere that a key can be specified for a function, e.g. sort, min, max, etc…:

>>> a.sort(key=default_sort_key)
>>> a[0]
2
>>> min(a, key=default_sort_key)
2

Notes

The key returned is useful for getting items into a canonical order that will be the same across platforms. It is not directly useful for sorting lists of expressions:

>>> a, b = x, 1/x

Since a has only 1 term, its value of sort_key is unaffected by order:

>>> a.sort_key() == a.sort_key('rev-lex')
True

If a and b are combined then the key will differ because there are terms that can be ordered:

>>> eq = a + b
>>> eq.sort_key() == eq.sort_key('rev-lex')
False
>>> eq.as_ordered_terms()
[x, 1/x]
>>> eq.as_ordered_terms('rev-lex')
[1/x, x]

But since the keys for each of these terms are independent of order’s value, they don’t sort differently when they appear separately in a list:

>>> sorted(eq.args, key=default_sort_key)
[1/x, x]
>>> sorted(eq.args, key=lambda i: default_sort_key(i, order='rev-lex'))
[1/x, x]

The order of terms obtained when using these keys is the order that would be obtained if those terms were factors in a product.

Although it is useful for quickly putting expressions in canonical order, it does not sort expressions based on their complexity defined by the number of operations, power of variables and others:

>>> sorted([sin(x)*cos(x), sin(x)], key=default_sort_key)
[sin(x)*cos(x), sin(x)]
>>> sorted([x, x**2, sqrt(x), x**3], key=default_sort_key)
[sqrt(x), x, x**2, x**3]
diofant.utilities.iterables.flatten(iterable, levels=None, cls=None)[source]

Recursively denest iterable containers.

>>> 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]

If you want to denest only a specified number of levels of nested containers, then set levels flag to the desired number of levels:

>>> ls = [[(-2, -1), (1, 2)], [(0, 0)]]
>>> flatten(ls, levels=1)
[(-2, -1), (1, 2), (0, 0)]

If cls argument is specified, it will only flatten instances of that class, for example:

>>> class MyOp(Basic):
...     pass
...
>>> flatten([MyOp(1, MyOp(2, 3))], cls=MyOp)
[1, 2, 3]

adapted from https://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks

diofant.utilities.iterables.group(seq, multiple=True)[source]

Splits a sequence into a list of lists of equal, adjacent elements.

Examples

>>> 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)]

See also

multiset

diofant.utilities.iterables.is_iterable(i, exclude=(<class 'str'>, <class 'dict'>, <class 'diofant.utilities.iterables.NotIterable'>))[source]

Return a boolean indicating whether i is Diofant iterable. True also indicates that the iterator is finite, i.e. you e.g. call list(…) on the instance.

When Diofant is working with iterables, it is almost always assuming that the iterable is not a string or a mapping, so those are excluded by default. If you want a pure Python definition, make exclude=None. To exclude multiple items, pass them as a tuple.

See also

is_sequence

Examples

>>> things = [[1], (1,), {1}, Tuple(1), (j for j in [1, 2]), {1: 2}, '1', 1]
>>> for i in things:
...     print(f'{is_iterable(i)} {type(i)}')
True <... 'list'>
True <... 'tuple'>
True <... 'set'>
True <class 'diofant.core.containers.Tuple'>
True <... 'generator'>
False <... 'dict'>
False <... 'str'>
False <... 'int'>
>>> is_iterable({}, exclude=None)
True
>>> is_iterable({}, exclude=str)
True
>>> is_iterable('no', exclude=str)
False
diofant.utilities.iterables.is_sequence(i, include=None)[source]

Return a boolean indicating whether i is a sequence in the Diofant sense. If anything that fails the test below should be included as being a sequence for your application, set ‘include’ to that object’s type; multiple types should be passed as a tuple of types.

Note: although generators can generate a sequence, they often need special handling to make sure their elements are captured before the generator is exhausted, so these are not included by default in the definition of a sequence.

See also

is_iterable

Examples

>>> 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
diofant.utilities.iterables.minlex(seq, directed=True, is_set=False, small=None)[source]

Return a tuple where the smallest element appears first; if directed is True (default) then the order is preserved, otherwise the sequence will be reversed if that gives a smaller ordering.

If every element appears only once then is_set can be set to True for more efficient processing.

If the smallest element is known at the time of calling, it can be passed and the calculation of the smallest element will be omitted.

Examples

>>> 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'
diofant.utilities.iterables.multiset(seq)[source]

Return the hashable sequence in multiset form with values being the multiplicity of the item in the sequence.

Examples

>>> multiset('mississippi')
{'i': 4, 'm': 1, 'p': 2, 's': 4}

See also

group

diofant.utilities.iterables.multiset_combinations(m, n, g=None)[source]

Return the unique combinations of size n from multiset m.

Examples

>>> 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)))

The number of combinations depends on the number of letters; the number of unique combinations depends on how the letters are repeated.

>>> s1 = 'abracadabra'
>>> s2 = 'banana tree'
>>> count(combinations, s1), count(multiset_combinations, s1)
(165, 23)
>>> count(combinations, s2), count(multiset_combinations, s2)
(165, 54)
diofant.utilities.iterables.multiset_partitions(multiset, m=None)[source]

Return unique partitions of the given multiset (in list form). If m is None, all multisets will be returned, otherwise only partitions with m parts will be returned.

If multiset is an integer, a range [0, 1, …, multiset - 1] will be supplied.

Counting

The number of partitions of a set is given by the bell number:

>>> len(list(multiset_partitions(5))) == bell(5) == 52
True

The number of partitions of length k from a set of size n is given by the Stirling Number of the 2nd kind:

>>> def s2(n, k):
...     from diofant import Dummy, Sum, binomial, factorial
...     if k > n:
...         return 0
...     j = Dummy()
...     arg = (-1)**(k-j)*j**n*binomial(k, j)
...     return 1/factorial(k)*Sum(arg, (j, 0, k)).doit()
...
>>> s2(5, 2) == len(list(multiset_partitions(5, 2))) == 15
True

These comments on counting apply to sets, not multisets.

Examples

>>> 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]]]

Only unique partitions are returned and these will be returned in a canonical order regardless of the order of the input:

>>> 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

If m is omitted then all partitions will be returned:

>>> 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]]]

Notes

When all the elements are the same in the multiset, the order of the returned partitions is determined by the partitions routine. If one is counting partitions then it is better to use the nT function.

diofant.utilities.iterables.multiset_permutations(m, size=None, g=None)[source]

Return the unique permutations of multiset m.

Examples

>>> [''.join(i) for i in multiset_permutations('aab')]
['aab', 'aba', 'baa']
>>> factorial(len('banana'))
720
>>> len(list(multiset_permutations('banana')))
60
diofant.utilities.iterables.numbered_symbols(prefix='x', cls=None, start=0, exclude=[], **assumptions)[source]

Generate an infinite stream of Symbols consisting of a prefix and increasing subscripts provided that they do not occur in \(exclude\).

Parameters:
  • prefix (str, optional) – The prefix to use. By default, this function will generate symbols of the form “x0”, “x1”, etc.

  • cls (class, optional) – The class to use. By default, it uses Symbol, but you can also use Wild or Dummy.

  • start (int, optional) – The start number. By default, it is 0.

Returns:

sym (Symbol) – The subscripted symbols.

diofant.utilities.iterables.ordered(seq, keys=None, default=True, warn=False)[source]

Return an iterator of the seq where keys are used to break ties in a conservative fashion: if, after applying a key, there are no ties then no other keys will be computed.

Two default keys will be applied if 1) keys are not provided or 2) the given keys don’t resolve all ties (but only if \(default\) is True). The two keys are \(_nodes\) (which places smaller expressions before large) and \(default_sort_key\) which (if the \(sort_key\) for an object is defined properly) should resolve any ties.

If warn is True then an error will be raised if there were no keys remaining to break ties. This can be used if it was expected that there should be no ties between items that are not identical.

Examples

The count_ops is not sufficient to break ties in this list and the first two items appear in their original order (i.e. the sorting is stable):

>>> list(ordered([y + 2, x + 2, x**2 + y + 3],
...              count_ops, default=False, warn=False))
[y + 2, x + 2, x**2 + y + 3]

The default_sort_key allows the tie to be broken:

>>> list(ordered([y + 2, x + 2, x**2 + y + 3]))
[x + 2, y + 2, x**2 + y + 3]

Here, sequences are sorted by length, then sum:

>>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]],
...              [lambda x: len(x), lambda x: sum(x)]]
>>> list(ordered(seq, keys, default=False, warn=False))
[[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]]

If warn is True, an error will be raised if there were not enough keys to break ties:

>>> list(ordered(seq, keys, default=False, warn=True))
Traceback (most recent call last):
...
ValueError: not enough keys to break ties

Notes

The decorated sort is one of the fastest ways to sort a sequence for which special item comparison is desired: the sequence is decorated, sorted on the basis of the decoration (e.g. making all letters lower case) and then undecorated. If one wants to break ties for items that have the same decorated value, a second key can be used. But if the second key is expensive to compute then it is inefficient to decorate all items with both keys: only those items having identical first key values need to be decorated. This function applies keys successively only when needed to break ties. By yielding an iterator, use of the tie-breaker is delayed as long as possible.

This function is best used in cases when use of the first key is expected to be a good hashing function; if there are no unique hashes from application of a key then that key should not have been used. The exception, however, is that even if there are many collisions, if the first group is small and one does not need to process all items in the list then time will not be wasted sorting what one was not interested in. For example, if one were looking for the minimum in a list and there were several criteria used to define the sort order, then this function would be good at returning that quickly if the first group of candidates is small relative to the number of items being processed.

diofant.utilities.iterables.ordered_partitions(n, m=None, sort=True)[source]

Generates ordered partitions of integer n.

Parameters:
  • ``m`` (int or None, optional) – By default (None) gives partitions of all sizes, else only those with size m. In addition, if m is not None then partitions are generated in place (see examples).

  • ``sort`` (bool, optional) – Controls whether partitions are returned in sorted order (default) when m is not None; when False, the partitions are returned as fast as possible with elements sorted, but when m|n the partitions will not be in ascending lexicographical order.

Examples

All partitions of 5 in ascending lexicographical:

>>> 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]

Only partitions of 5 with two parts:

>>> for p in ordered_partitions(5, 2):
...     print(p)
[1, 4]
[2, 3]

When m is given, a given list objects will be used more than once for speed reasons so you will not see the correct partitions unless you make a copy of each as it is generated:

>>> list(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]]

When n is a multiple of m, the elements are still sorted but the partitions themselves will be unordered if sort is False; the default is to return them in ascending lexicographical order.

>>> for p in ordered_partitions(6, 2):
...     print(p)
[1, 5]
[2, 4]
[3, 3]

But if speed is more important than ordering, sort can be set to False:

>>> for p in ordered_partitions(6, 2, sort=False):
...     print(p)
[1, 5]
[3, 3]
[2, 4]

References

diofant.utilities.iterables.partitions(n, m=None, k=None, size=False)[source]

Generate all partitions of positive integer, n.

Parameters:
  • ``m`` (integer (default gives partitions of all sizes)) – limits number of parts in partition (mnemonic: m, maximum parts). Default value, None, gives partitions from 1 through n.

  • ``k`` (integer (default gives partitions number from 1 through n)) – limits the numbers that are kept in the partition (mnemonic: k, keys)

  • ``size`` (bool (default False, only partition is returned)) – when True then (M, P) is returned where M is the sum of the multiplicities and P is the generated partition.

  • Each partition is represented as a dictionary, mapping an integer

  • to the number of copies of that integer in the partition. For example,

  • the first partition of 4 returned is {4 (1}, “4: one of them”.)

Examples

The numbers appearing in the partition (the key of the returned dict) are limited with k:

>>> from diofant.utilities.iterables import partitions
>>> for p in partitions(6, k=2):
...     print(p)
{2: 3}
{2: 2, 1: 2}
{2: 1, 1: 4}
{1: 6}

The maximum number of parts in the partition (the sum of the values in the returned dict) are limited with m:

>>> for p in partitions(6, m=2):
...     print(p)
...
{6: 1}
{5: 1, 1: 1}
{4: 1, 2: 1}
{3: 2}

Note that the _same_ dictionary object is returned each time. This is for speed: generating each partition goes quickly, taking constant time, independent of n.

>>> list(partitions(6, k=2))
[{1: 6}, {1: 6}, {1: 6}, {1: 6}]

If you want to build a list of the returned dictionaries then make a copy of them:

>>> [p.copy() for p in partitions(6, k=2)]
[{2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}]
>>> [(M, p.copy()) for M, p in partitions(6, k=2, size=True)]
[(3, {2: 3}), (4, {1: 2, 2: 2}), (5, {1: 4, 2: 1}), (6, {1: 6})]

References

Notes

Modified from Tim Peter’s version to allow for k and m values.

diofant.utilities.iterables.permute_signs(t)[source]

Return iterator in which the signs of non-zero elements of t are permuted.

Examples

>>> list(permute_signs((0, 1, 2)))
[(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2)]
diofant.utilities.iterables.postorder_traversal(node, keys=None)[source]

Do a postorder traversal of a tree.

This generator recursively yields nodes that it has visited in a postorder fashion. That is, it descends through the tree depth-first to yield all of a node’s children’s postorder traversal before yielding the node itself.

Parameters:
  • node (diofant expression) – The expression to traverse.

  • keys ((default None) sort key(s)) – The key(s) used to sort args of Basic objects. When None, args of Basic objects are processed in arbitrary order. If key is defined, it will be passed along to ordered() as the only key(s) to use to sort the arguments; if key is simply True then the default keys of ordered will be used (node count and default_sort_key).

Yields:

subtree (diofant expression) – All of the subtrees in the tree.

Examples

>>> from diofant.abc import w

The nodes are returned in the order that they are encountered unless key is given; simply passing key=True will guarantee that the traversal is unique.

>>> list(postorder_traversal(w + (x + y)*z, keys=True))
[w, z, x, y, x + y, z*(x + y), w + z*(x + y)]
diofant.utilities.iterables.rotate_left(x, y)[source]

Left rotates a list x by the number of steps specified in y.

Examples

>>> a = [0, 1, 2]
>>> rotate_left(a, 1)
[1, 2, 0]
diofant.utilities.iterables.rotate_right(x, y)[source]

Right rotates a list x by the number of steps specified in y.

Examples

>>> a = [0, 1, 2]
>>> rotate_right(a, 1)
[2, 0, 1]
diofant.utilities.iterables.runs(seq, op=<built-in function gt>)[source]

Group the sequence into lists in which successive elements all compare the same with the comparison operator, op: op(seq[i + 1], seq[i]) is True from all elements in a run.

Examples

>>> import operator
>>> 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=operator.ge)
[[0, 1, 2, 2], [1, 4], [3], [2, 2]]
diofant.utilities.iterables.sift(seq, keyfunc)[source]

Sift the sequence, seq into a dictionary according to keyfunc.

OUTPUT: each element in expr is stored in a list keyed to the value of keyfunc for the element.

Examples

>>> from collections import defaultdict
>>> sift(range(5), lambda x: x % 2) == defaultdict(int, {0: [0, 2, 4], 1: [1, 3]})
True

sift() returns a defaultdict() object, so any key that has no matches will give [].

>>> dl = sift([x], lambda x: x.is_commutative)
>>> dl == defaultdict(list, {True: [x]})
True
>>> dl[False]
[]

Sometimes you won’t know how many keys you will get:

>>> (sift([sqrt(x), exp(x), (y**x)**2],
...       lambda x: x.as_base_exp()[0]) ==
...  defaultdict(list, {E: [exp(x)], x: [sqrt(x)], y: [y**(2*x)]}))
True

If you need to sort the sifted items it might be better to use ordered which can economically apply multiple sort keys to a squence while sorting.

See also

ordered

diofant.utilities.iterables.signed_permutations(t)[source]

Return iterator in which the signs of non-zero elements of t and the order of the elements are permuted.

Examples

>>> 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)]
diofant.utilities.iterables.subsets(seq, k=None, repetition=False)[source]

Generates all k-subsets (combinations) from an n-element set, seq.

A k-subset of an n-element set is any subset of length exactly k. The number of k-subsets of an n-element set is given by binomial(n, k), whereas there are 2**n subsets all together. If k is None then all 2**n subsets will be returned from shortest to longest.

Examples

subsets(seq, k) will return the n!/k!/(n - k)! k-subsets (combinations) without repetition, i.e. once an item has been removed, it can no longer be “taken”:

>>> from diofant.utilities.iterables import subsets
>>> 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) will return the (n - 1 + k)!/k!/(n - 1)! combinations with repetition:

>>> list(subsets([1, 2], 2, repetition=True))
[(1, 1), (1, 2), (2, 2)]

If you ask for more items than are in the set you get the empty set unless you allow repetitions:

>>> 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)]
diofant.utilities.iterables.unflatten(iter, n=2)[source]

Group iter into tuples of length n. Raise an error if the length of iter is not a multiple of n.

diofant.utilities.iterables.uniq(seq, result=None)[source]

Yield unique elements from seq as an iterator. The second parameter result is used internally; it is not necessary to pass anything for this.

Examples

>>> 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]]