Skip to main content

RingSeqPy

PyPI - Version CI Python Version from PEP 621 TOML

A Pythonic class for sequences considered circular — where the element after the last wraps back to the first.

RingSeqPy is a small, zero-dependency library exposing a single generic RingSeq[T] class that wraps any Iterable[T], stores it internally as an immutable tuple, and implements the Python Sequence protocol circularly. Instances are hashable, orderable, and interoperable: RingSeq('ABC'), RingSeq(['A','B','C']), and RingSeq(('A','B','C')) all compare equal.

Installation

pip install ring-seq-py

Working for Python 3.10 and above.

Quick start

>>> from ring_seq import RingSeq

>>> # Indexing wraps around
>>> RingSeq([10, 20, 30])[4]
20

>>> # Slicing wraps around too; transformations return a new RingSeq,
>>> # unwrap with .to_list() / .to_tuple() / .to_str()
>>> RingSeq([0, 1, 2]).rotate_right(1).to_list()
[2, 0, 1]

>>> # Comparison up to rotation
>>> RingSeq([0, 1, 2]).is_rotation_of([2, 0, 1])
True

>>> # Canonical (necklace) form for deduplication
>>> RingSeq([2, 0, 1]).canonical().to_list()
[0, 1, 2]

>>> # Symmetry detection
>>> RingSeq([0, 1, 0, 1]).rotational_symmetry()
2

>>> # Strings work naturally; to_str() rejoins
>>> RingSeq('RING').rotate_right(1).to_str()
'GRIN'

Operations

Native sequence protocol (circular)

Method Description
rs[i] Element at circular index (any integer wraps)
rs[i:j], rs[i:j:k] Circular slice (can exceed ring length; negative step traverses backward)
len(rs), iter(rs), reversed(rs), x in rs Standard protocol, no surprises
rs == other, hash(rs), min(rings) Positional equality; lexicographic ordering
get(i, default=None) Like rs[i], but returns default on an empty ring
index(value, start=0, stop=None) Circular first-occurrence lookup
index_of_slice(that, from_=0) Circular index of a contiguous (possibly wrapping) slice, or None
contains_slice(that) Whether a slice occurs in the ring, wrapping included

Unwrap

Method Description
to_list() Return a new list
to_tuple() Return the internal tuple
to_str(sep='') Join elements into a str

Indexing helper

Method Description
index_from(i) Normalize a circular index to [0, len)

Transforming

Method Description
rotate_right(step) Rotate right by step (negative = left)
rotate_left(step) Rotate left by step (negative = right)
start_at(i) Rotate so circular index i is first
reflect_at(i=0) Reflect so circular index i is the axis head

Slicing primitives

Method Description
take_while(p, from_=0) Longest prefix from from_ satisfying p
drop_while(p, from_=0) Remainder after that prefix
span(p, from_=0) (take_while, drop_while) in one call

Iterating

Method Description
rotations() All n rotations (lazy)
reflections() Original + reflection (lazy)
reversions() Original + reversal (lazy)
rotations_and_reflections() All 2n variants (lazy)
windows(size) n sliding windows of fixed size, wrapping the seam
grouped(size) ceil(n / size) fixed-size blocks, last one wraps the seam
zip_with_index(from_=0) Elements paired with their circular indices

Comparing

Method Description
is_rotation_of(that) Same elements, possibly rotated?
is_reflection_of(that) Same elements, possibly reflected?
is_reversion_of(that) Same elements, possibly reversed?
is_rotation_or_reflection_of(that) Either of the above?
align_to(that) k such that start_at(k) == that, or None
hamming_distance(that) Positional mismatches (same size required)
min_rotational_hamming_distance(that) Minimum distance over all rotations

Necklace

Method Description
canonical_index() Index of lex-smallest rotation (two-pointer minimal rotation, O(n) time, O(1) space)
canonical() Lex-smallest rotation (necklace form)
bracelet() Lex-smallest under rotation and reflection

Symmetry

Method Description
rotational_symmetry() Order of rotational symmetry
symmetry_indices() Shifts where the ring equals its reversal rotated left
reflectional_symmetry_axes() Full axis geometry (Vertex / Edge pairs)
symmetry() Number of reflectional symmetry axes

Naming convention

RingSeq subclasses collections.abc.Sequence, so native Python protocols do the work where they map cleanly — rs[i] for indexing, rs[i:j] for slicing, x in rs for containment. A few methods are deliberately renamed from the Scala/Rust counterparts to be Pythonic:

This library Elsewhere
rs[i] apply (Rust), applyO (Scala)
rs[i:j], rs[i:j:k] slice (Rust), sliceO (Scala)
windows windows (Rust), slidingO (Scala)
grouped chunks (Rust)
zip_with_index enumerate (Rust)

RingSeq.index(value, start=0, stop=None) overrides Sequence.index with circular semantics: without a stop it searches one full revolution and returns an index in [0, len).

Use cases

  • Bioinformatics — circular DNA/RNA sequence alignment and comparison
  • Graphics — polygon vertex manipulation, closed curve operations
  • Procedural generation — tile rings, symmetry-aware pattern generation
  • Music theory — pitch-class sets, chord inversions
  • Combinatorics — necklace/bracelet enumeration, Burnside's lemma
  • Embedded / robotics — circular sensor arrays, rotary encoder positions

Other languages

The same library, adapted for the specific idiom, is available also for:

License

Licensed under either of

at your option.

Metadata

Release files for ring-seq-py 2.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ring-seq-py 2.2.0
File Size Uploaded
ring_seq_py-2.2.0.tar.gz 18.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ring-seq-py 2.2.0
File Interpreter ABI Platform
ring_seq_py-2.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 34.9 kB

Release files / ring_seq_py-2.2.0.tar.gz

Download URL ring_seq_py-2.2.0.tar.gz
Size 18.0 kB
Tags Source
SHA-256 checksum
How to use checksums
49b152d9bd90cbd50e4f0c60bf33835fc417b4a03daab92045f11b5123fa5c04
BLAKE2b-256 checksum
How to use checksums
4a0b25231c0b13a9f38c56afa6bb22ae28a599011de42d1a542a74f6ff015cce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 10, 2026.

Transparency log

Release files / ring_seq_py-2.2.0-py3-none-any.whl

Download URL ring_seq_py-2.2.0-py3-none-any.whl
Size 16.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dabdc04495039cd0aafd1a02d48831e52e63e2d9154bbb31375167baaf2e57ca
BLAKE2b-256 checksum
How to use checksums
f49e6554b6e54a63ec7efe86ecec8b7e7efe77df1e98c617c907c1bdc9119383
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.2.0 This release

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.0.0

2 release files

1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page