The EzSequence library for Python can easily generate custom iterable sequences of numbers for you.
| ezsequence | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| LICENSE.txt | ||
| pyproject.toml | ||
| README.md | ||
| runtests.py | ||
EzSequence
A quick and dirty sequence generator for Python.
About
- EzSequence uses a fluent interface to strive for a self-documenting code approach. It works like the Builder pattern.
- EzSequence produces iterators that you can use in your FOR loops, your list comprehensions or to be converted to a list all at once.
- EzSequence supports infinite sequences but has safety built in.
Basic Usage
from ezsequence import *
seq = sequence_from(1).to(5)
print(seq)
Full Usage
Static Methods
There is only one!
sequence_from()
This function starts your sequence with an initial value and some default behavior. From there, you can customize it with any of the fluent methods listed below.
Fluent Methods
| Method | Description | Example | Output |
|---|---|---|---|
| .by(increment: int) | Optional. Specifies a gap between values. Default is 1. Cannot be used with .with_increment(). |
sequence_from(1) .to(5) .by(2) |
[1, 3, 5] |
| .with_increment(increment_func: Callable[[int, int], int]) | Optional. Specifies the translation of the value on each iteration. By default, value is incremented by 1. | sequence .from(1) .to(5) .with_increment(lambda index, value: value + 2) |
[1, 3, 5] |
| .until(condition: Callable[[int, int], int]) | Optional. Specifies a terminating condition in the sequence. Value is inclusive. In other words, once the condition is met, the next iteration will end the sequence. Multiple .until() calls are permitted. Otherwise, it is the same as .to(). |
sequence_from(1) .until(lambda index, value: value == 5) |
[1, 2, 3, 4, 5] |
| .as_long_as(condition: Callable[[int, int], int]) | Optional. Specifies a terminating condition in the sequence. Value is exclusive. In other words, once the condition is violated, the current iteration will end the sequence. Multiple .as_long_as() calls are permitted. | sequence_from(1) .as_long_as(lambda index, value: value <= 5) |
[1, 2, 3, 4, 5] |
| .when(condition: Callable[[int, int], int]) | Optional. Specifies a condition for including this value in the sequence output. By default, all values are included. Multiple .when() calls are supported. Evluations do not terminate the sequence. | sequence_from(1) .to(5) .when(lambda index, value: value % 2 == 1) |
[1, 3, 5] |
| .not_when(condition: Callable[[int, int], int]) | Optional. Specifies a condition for excluding values, overriding any .when() condition that included them. By default, there are no exclusions. Multiple .not_when() calls are supported. Evaluations do not terminate the sequence. | sequence_from(1) .to(5) .not_when(lambda index, value: value % 2 == 0) |
[1, 3, 5] |
| .safely(max_attempts: int) | Optional. Prevents unintended infinite loops caused by .when() and .not_when() filters which will hang in the while loop that searches for the next unfiltered vlaue in the sequence. Takes an optional parameter for the max number of attempts to find an unfiltered value. Default max attempts is 10000. | sequence_from(1) .to(5) .when(lambda index, value: value < 0) .safely(100) |
Exception: Safe iteration limit exceeded. 100 attempts exceeded. |
| .unsafely() | Optional. Allows unintended infinite loops caused by .when() and .not_when() filters which may hang in the _while_loop that searchs for the next unfiltered value in the sequence. |
sequence_from(1) .with_increment(lambda index, value: random.Random() .randint(1, 1000)) .as_long_as(lambda index, value: value != 50) .unsafely() |
(No exception but may hang indefinitely) |
| .translate_as(projection: Callable[[int, int], any]) | Optional. Specifies a function to convert each element that is returned by the iterator. | sequence_from(5) .to(9) .translate_as(lambda index, value: value - 4) |
[1, 2, 3, 4, 5] |
| .reset() | Rewinds the sequence to the beginning so it can be reused. | seq.reset() |
N/A |
More Examples
Odds
seq = sequence_from(1).to(5) \
.when(lambda index, value: value % 2 == 1)
Evens
seq = sequence_from(1).to(5) \
.when(lambda index, value: value % 2 == 0)
Backward
seq = sequence_from(1) \
.by(-1) \
.until(lambda index, value: value == -5)
Random Bytes
import random
rnd = random.Random()
seq = sequence_from(1).to(8) \
.translate_as(lambda index, value: rnd.randint(0, 255))
data = list(seq)
Random AlphaNumeric Text
import random
rnd = random.Random()
seq = sequence_from(1).to(8) \
.translate_as(lambda index, value: chr(rnd.randint(1, 26) + 64))
data = "".join(seq)
Reset Example
import random
rnd = random.Random()
seq = sequence_from(1).to(8) \
.translate_as(lambda index, value: chr(rnd.randint(1, 26) + 64))
data1 = "".join(seq)
seq.reset()
data2 = "".join(seq)
Random CSV values
import random
rnd = random.Random()
field_count = 5
row_count = 3
def create_field_data(data_seq):
data_seq.reset()
return "".join(data_seq)
def create_row(field_seq):
field_seq.reset()
return ",".join(field_seq)
data_seq = sequence_from(1).to(8) \
.translate_as(lambda index, value: chr(rnd.randint(1, 26) + 64))
field_seq = sequence_from(1).to(field_count) \
.translate_as(lambda index, value: "\"" + create_field_data(data_seq) + "\"")
row_seq = sequence_from(1).to(row_count)
for row in row_seq:
print(create_row(field_seq))
Guid
import random
rnd = random.Random()
section_generators = \
[
sequence_from(1).to(8).translate_as(lambda index, value: hex(rnd.randint(0, 15))[2:3]),
sequence_from(1).to(4).translate_as(lambda index, value: hex(rnd.randint(0, 15))[2:3]),
sequence_from(1).to(4).translate_as(lambda index, value: hex(rnd.randint(0, 15))[2:3]),
sequence_from(1).to(4).translate_as(lambda index, value: hex(rnd.randint(0, 15))[2:3]),
sequence_from(1).to(12).translate_as(lambda index, value: hex(rnd.randint(0, 15))[2:3])
]
sections = ["".join(generator) for generator in section_generators]
guid = "-".join(sections)
print(guid)
Factorials
from functools import reduce
factorial_of = 5
factors = sequence_from(factorial_of) \
.with_increment(lambda index, value: value - 1) \
.until(lambda index, value: value == 1)
factorial = reduce(lambda running, value: running * value, factors)
print(list(factors.reset()))
print(factorial)
Fibonacci
import itertools
class Fibonacci:
def __init__(self):
self.previous2 = 0
self.previous1 = 1
def calculate_fibonacci(self, value):
next_value = self.previous1 + self.previous2
self.previous2 = self.previous1
self.previous1 = next_value
return next_value
def sequence(self):
seq = sequence_from(1).to(20) \
.translate_as(lambda index, value: self.calculate_fibonacci(value)) \
.as_long_as(lambda index, value: value < 500000000)
return itertools.chain([1], seq)
fib = list(Fibonacci().sequence())
print(fib)
Multiple when, not_when, until and as_long_as
seq = sequence_from(1).to(50) \
.by(3) \
.when(lambda index, value: value >= 10) \
.when(lambda index, value: value % 2 == 1) \
.when_not(lambda index, value: value == 25) \
.as_long_as(lambda index, value: value <= 40) \
.as_long_as(lambda index, value: value != 38) \
.safely(10)
print(list(seq))