"""Sequence."""
import pandas as pd
from extepy import cycleperm as _cycleperm, swap as _swap, prioritize as _prioritize
from .matcher import _get_matcher
from .typing import Uniquable
def _unique_sequence(values, matcher=None, dissemble=True):
if dissemble:
values = matcher.disassemble(values)
results = []
for value in values:
for result in results:
if matcher.eq(result, value):
break
else:
results.append(value)
results = matcher.assemble(results)
return results
[docs]
def unique(values, *, key=None):
"""Drop duplications with original order kept.
Parameters:
values (iterable):
key (callable):
Returns:
Unique values
Example:
>>> unique([1, 2, 2, 3, 2, 1, 2])
[1, 2, 3]
>>> unique((1, 2, 2, 3, 2, 1, 2))
(1, 2, 3)
>>> unique('Hello')
'Helo'
"""
if len(values) == 0 or isinstance(values, dict):
return values
if isinstance(values, Uniquable):
matcher = _get_matcher(values, key=key)
return _unique_sequence(values, matcher=matcher)
return pd.unique(values)
[docs]
def count_unique(values, *, key=None):
"""Count the number of distinct elements.
Parameters:
values (iterable)
key (callable)
Returns:
int: Number of distinct elements.
Examples:
>>> count_unique([1, 2, 2, 3, 2, 1, 2])
3
>>> count_unique('Hello')
4
"""
result = len(unique(values, key=key))
return result
[docs]
def min_repetend_len(values, *, allow_frac=True, key=None):
"""Get minimum length of repetends.
Parameters:
values (list): List of values as a sequence.
allow_frac (bool): Whether to allow partial repetend at the end of sequence.
key : A object to be used to determine whether two values are the same.
Returns:
int: Minimum length of repetends.
Examples:
>>> min_repetend_len([1, 1, 1, 1])
1
>>> min_repetend_len([1, 2, 1, 2])
2
>>> min_repetend_len([1, 2, 1, 3])
4
>>> min_repetend_len([1, 2, 1, 3, 1, 2, 1, 3])
4
>>> min_repetend_len([1, 2, 1, 2, 1, 2, 1], allow_frac=False)
7
"""
length = len(values)
if length == 0:
return 0
matcher = _get_matcher(values, key=key)
for l in range(1, length): # noqa: E741
if (not allow_frac) and (length % l > 0):
continue
for i in range(length-l):
if not matcher.eq(values[i], values[i+l]):
break
else:
return l
return length
[docs]
def cycleperm(values, /, cycle):
"""Permutate a list according to cycle notation.
Parameters:
values (list): Sequence to permutate.
cycle (list): Permutation rule in cyclc notation.
Returns:
list: Permutated sequence.
Examples:
Permutate a list of strings.
>>> cycleperm(["a", "b", "c", "d", "e", "f", "g"], cycle=[1, 2, 4])
['a', 'c', 'e', 'd', 'b', 'f', 'g']
Permutate a list of integers.
>>> cycleperm(list(range(6)), cycle=[0, 1, 2])
[1, 2, 0, 3, 4, 5]
See also:
https://extepy.github.io/seq.html#extepy.cycleperm
"""
return _cycleperm(values, cycle)
[docs]
def swap(values, /, i=0, j=1):
"""Swap two elements in a list.
Parameters:
values (list): Sequence to permutate.
i (int): Index of the first element to swap.
j (int): Index of the second element to swap.
Returns:
list: Swapped sequence.
Examples:
Swap two elements for a list of strings.
>>> swap(["a", "b", "c", "d", "e", "f", "g"], i=1, j=2)
['a', 'c', 'b', 'd', 'e', 'f', 'g']
Swap two elements for a list of integers.
>>> swap(list(range(6)), i=1, j=2)
[0, 2, 1, 3, 4, 5]
See also:
https://extepy.github.io/seq.html#extepy.swap
"""
return _swap(values, i=i, j=j)
[docs]
def prioritize(values, *, index, dup="multiple"):
"""Move some elements in the sequence to the beginning.
Parameters:
values (list | tuple | str): Sequence to permutate.
index (int | list[int]): Index of the elements to move to the beginning.
The index can be negative. If there are duplicated index values, the same
element will appear multiple times.
dup (``{"multiple", "unique", "raise"}``): Specify how to deal with the case that
the same position is prioritized mutliple times.
``"multiple"``: The same element will appear multiple times.
``"unique"``: The same element will appear only once.
``"raise"``: Raise an error.
Returns:
list | tuple | str:
Examples:
Move a single positional argument to the beginning.
>>> prioritize(["a", "b", "c", "d"], index=-2)
['c', 'a', 'b', 'd']
Move multiple positional arguments to the beginning.
>>> prioritize(["a", "b", "c", "d"], index=[0, 2, -2])
['a', 'c', 'c', 'b', 'd']
>>> prioritize(["a", "b", "c", "d"], index=[0, 2, -2], dup="unique")
['a', 'c', 'b', 'd']
See also:
https://extepy.github.io/seq.html#extepy.prioritize
"""
return _prioritize(values, index, dup=dup)