Kothon
Kothon is a Python library designed to bring the elegance and functionality of Kotlin's Sequence class into the Python
ecosystem. With an emphasis on functional programming paradigms, Kothon enables Python developers to leverage
lazy-evaluated sequences, allowing for efficient and expressive data processing pipelines.
Features
- Functional Programming: Embrace functional programming with a rich set of operators
like
map
, filter
, reduce
, and much more, enabling you to write more declarative and concise code. - Strongly Typed: Leveraging Python's type hints for clearer, more robust code.
- Lazy Evaluation: Kothon sequences are evaluated lazily, meaning computations are deferred until the value is
needed, enhancing performance especially for large datasets.
- Interoperability: Seamlessly integrate with existing Python codebases, enjoying the benefits of Kotlin-like
sequences without disrupting your current workflow.
- Easy to Use: Kothon's API is designed to be intuitive for both Python and Kotlin developers, ensuring a smooth
learning curve.
Installation
To install Kothon, simply run the following command in your terminal:
pip install kothon
Quick Start
Here's a quick example to get you started with Kothon:
from kothon import Seq
input_data = [0, 1, None, 2, 3, None, 4]
result = Seq(input_data) \
.filter_not_none() \
.filter(lambda x: x % 2 == 0) \
.map(lambda x: x * 2) \
.to_list()
print(result)
Alternatively, utilize pipe
for a more Pythonic approach.
from kothon import pipe, filter_not_none, kothon_filter, kothon_map
input_data = [0, 1, None, 2, 3, None, 4]
result = pipe(
input_data,
filter_not_none,
kothon_filter(lambda x: x % 2 == 0),
kothon_map(lambda x: x * 2),
).to_list()
print(result)
Existing functions in Seq
filter
Filters elements based on a predicate.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3, 4, 5])
>>> seq.filter(lambda x: x % 2 == 0).to_list()
[2, 4]
>>>
filter_not_none
Filters out None
values from the sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, None, 2, None, 3])
>>> seq.filter_not_none().to_list()
[1, 2, 3]
>>>
filter_is_instance
Filters elements of the sequence based on their type.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 'two', 3, 'four', 5])
>>> seq.filter_is_instance(str).to_list()
['two', 'four']
>>>
map
Applies a function to each element in the sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3])
>>> seq.map(lambda x: x * x).to_list()
[1, 4, 9]
>>>
map_not_none
Applies a function to each element and filters out None
results.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3, 4])
>>> seq.map_not_none(lambda x: x * 2 if x % 2 == 0 else None).to_list()
[4, 8]
>>>
flat_map
Applies a function to each element that returns an iterable and flattens the result.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3])
>>> seq.flat_map(lambda x: [x, -x]).to_list()
[1, -1, 2, -2, 3, -3]
>>>
flatten
Flattens a sequence of iterables into a single sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq([[1, 2], [3, 4], [5]])
>>> seq.flatten().to_list()
[1, 2, 3, 4, 5]
>>>
associate
Transforms elements into key-value pairs and aggregates them into a dictionary.
>>> from kothon import Seq
>>>
>>> seq = Seq(["a", "bb", "ccc"])
>>> seq.associate(lambda x: (x, len(x)))
{'a': 1, 'bb': 2, 'ccc': 3}
>>>
associate_by
Creates a dictionary from the sequence by determining keys using a specified key selector function.
>>> from kothon import Seq
>>>
>>> seq = Seq(["apple", "banana", "cherry"])
>>> seq.associate_by(lambda x: x[0])
{'a': 'apple', 'b': 'banana', 'c': 'cherry'}
>>>
associate_with
Creates a dictionary from the sequence with elements as keys and values determined by a value selector function.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3])
>>> seq.associate_with(lambda x: x * x)
{1: 1, 2: 4, 3: 9}
>>>
group_by
Groups elements based on a key function.
>>> from kothon import Seq
>>>
>>> seq = Seq(["one", "two", "three"])
>>> seq.group_by(len)
{3: ['one', 'two'], 5: ['three']}
>>>
to_list
Converts the sequence to a list.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3])
>>> seq.to_list()
[1, 2, 3]
>>>
to_set
Converts the sequence to a set.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 2, 3, 3])
>>> seq.to_set()
{1, 2, 3}
>>>
all
Checks if all elements satisfy a condition.
>>> from kothon import Seq
>>>
>>> seq = Seq([2, 4, 6])
>>> seq.all(lambda x: x % 2 == 0)
True
>>> seq.all(lambda x: x > 5)
False
>>>
none
Checks if no elements satisfy a condition.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 3, 5])
>>> seq.none(lambda x: x % 2 == 0)
True
>>> seq.none(lambda x: x < 5)
False
>>>
any
Checks if any elements satisfy a condition.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3])
>>> seq.any(lambda x: x % 2 == 0)
True
>>> seq.any(lambda x: x > 5)
False
>>>
max
Finds the maximum element.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 3, 2])
>>> seq.max()
3
>>>
max_or_none
Finds the maximum element, or returns None
for an empty sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 3, 2])
>>> seq.max_or_none()
3
>>> seq = Seq([])
>>> seq.max_or_none()
>>>
max_by
Finds the element which maximizes a specified function.
>>> from kothon import Seq
>>>
>>> seq = Seq(['a', 'abc', 'ab'])
>>> seq.max_by(len)
'abc'
>>>
max_by_or_none
Like max_by
, but returns None
for an empty sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq(['a', 'abc', 'ab'])
>>> seq.max_by_or_none(len)
'abc'
>>> seq = Seq([])
>>> seq.max_by_or_none(len)
>>>
min
Finds the minimum element.
>>> from kothon import Seq
>>>
>>> seq = Seq([3, 1, 2])
>>> seq.min()
1
>>>
min_or_none
Finds the minimum element, or returns None
for an empty sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 3, 2])
>>> seq.min_or_none()
1
>>> seq = Seq([])
>>> seq.min_or_none()
>>>
min_by
Finds the element which minimizes a specified function.
>>> from kothon import Seq
>>>
>>> seq = Seq(['abc', 'a', 'ab'])
>>> seq.min_by(len)
'a'
>>>
min_by_or_none
Like min_by
, but returns None
for an empty sequence.
>>> from kothon import Seq
>>>
>>> seq = Seq(['abc', 'a', 'ab'])
>>> seq.min_by_or_none(len)
'a'
>>> seq = Seq([])
>>> seq.min_by_or_none(len)
>>>
single
Returns the single element of the sequence, and throws an error if the sequence does not contain exactly one element.
>>> from kothon import Seq
>>>
>>> Seq([9]).single()
9
>>>
>>>
>>>
single_or_none
Returns the single element of the sequence, or None
if the sequence is empty. Throws an error if the sequence contains more than one element.
>>> from kothon import Seq
>>>
>>> Seq([9]).single_or_none()
9
>>> Seq([]).single_or_none()
>>> Seq([1, 2]).single_or_none()
>>>
first
Returns the first element of the sequence. Throws an error if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([7, 8, 9]).first()
7
>>>
>>>
first_or_none
Returns the first element of the sequence, or None
if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([7, 8, 9]).first_or_none()
7
>>> Seq([]).first_or_none()
>>>
last
Returns the last element of the sequence. Throws an error if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([7, 8, 9]).last()
9
>>>
>>>
last_or_none
Returns the last element of the sequence, or None
if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([7, 8, 9]).last_or_none()
9
>>> Seq([]).last_or_none()
>>>
drop
Returns a new sequence with the first n
elements removed.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4]).drop(2).to_list()
[3, 4]
>>>
drop_while
Returns a new sequence by dropping elements as long as the predicate is true.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3, 4, 1])
>>> seq.drop_while(lambda x: x < 3).to_list()
[3, 4, 1]
>>>
take
Returns a new sequence containing the first n
elements.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4]).take(2).to_list()
[1, 2]
>>>
take_while
Returns a new sequence by taking elements as long as the predicate is true.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3, 4, 1])
>>> seq.take_while(lambda x: x < 3).to_list()
[1, 2]
>>>
sorted
Returns a new sequence with elements sorted in ascending order.
>>> from kothon import Seq
>>>
>>> Seq([3, 1, 4]).sorted().to_list()
[1, 3, 4]
>>>
sorted_by
Sorts elements by a specified key function.
>>> from kothon import Seq
>>>
>>> seq = Seq(['apple', 'banana', 'cherry'])
>>> seq.sorted_by(lambda x: x[0]).to_list()
['apple', 'banana', 'cherry']
>>>
sorted_desc
Returns a new sequence with elements sorted in descending order.
>>> from kothon import Seq
>>>
>>> Seq([3, 1, 4]).sorted_desc().to_list()
[4, 3, 1]
>>>
sorted_by_desc
Sorts elements by a specified key function in descending order.
>>> from kothon import Seq
>>>
>>> seq = Seq(['apple', 'banana', 'cherry'])
>>> seq.sorted_by_desc(lambda x: x[0]).to_list()
['cherry', 'banana', 'apple']
>>>
chunked
Splits the sequence into chunks of the specified size.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4, 5]).chunked(2).to_list()
[[1, 2], [3, 4], [5]]
>>>
enumerate
Adds an index to each element of the sequence.
>>> from kothon import Seq
>>>
>>> Seq(['a', 'b', 'c']).enumerate().to_list()
[(0, 'a'), (1, 'b'), (2, 'c')]
>>>
shuffled
Returns a new sequence with elements shuffled in random order.
>>> import random
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3, 4, 5])
>>> rng = random.Random(42)
>>> seq.shuffled(rng).to_list()
[4, 2, 3, 5, 1]
>>>
reduce
Reduces the sequence to a single value by applying a binary operation. Throws an error if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4]).reduce(lambda x, y: x + y)
10
>>>
reduce_or_none
Like reduce
, but returns None
for an empty sequence.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4]).reduce_or_none(lambda x, y: x + y)
10
>>> Seq([]).reduce_or_none(lambda x, y: x + y)
>>>
sum
Sums the elements in the sequence. Throws an error if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4]).sum()
10
>>>
sum_or_none
Calculates the sum of all elements in the sequence, or returns None
if the sequence is empty.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 3, 4]).sum_or_none()
10
>>> Seq([]).sum_or_none()
>>>
distinct
Returns a new sequence with distinct elements.
>>> from kothon import Seq
>>>
>>> Seq([1, 2, 2, 3, 3]).distinct().to_list()
[1, 2, 3]
>>>
distinct_by
Returns a new sequence with elements that are distinct based on the specified key function.
>>> from kothon import Seq
>>>
>>> seq = Seq(['apple', 'banana', 'apricot'])
>>> seq.distinct_by(lambda x: x[0]).to_list()
['apple', 'banana']
>>>
for_each
Applies an action to each element of the sequence.
>>> from kothon import Seq
>>>
>>> result = []
>>> Seq([1, 2, 3]).for_each(lambda x: print(x))
1
2
3
>>>
join_to_string
Concatenates elements of the sequence into a single string with specified separators and optional prefix/suffix.
>>> from kothon import Seq
>>>
>>> seq = Seq(['apple', 'banana', 'cherry'])
>>> seq.join_to_string(separator=", ", prefix="[", suffix="]")
'[apple, banana, cherry]'
>>>
partition
Splits the sequence into two sequences based on a predicate. The first sequence contains elements for which the predicate is true, and the second contains elements for which it is false.
>>> from kothon import Seq
>>>
>>> seq = Seq([1, 2, 3, 4, 5])
>>> true_part, false_part = seq.partition(lambda x: x % 2 == 0)
>>> true_part
[2, 4]
>>> false_part
[1, 3, 5]
>>>
Contributing
We welcome contributions! If you have improvements or bug fixes, please feel free to create a pull request.
Acknowledgments
Kothon is inspired by the Kotlin Sequence class and the broader functional programming paradigm. We are grateful to the
Kotlin community for their innovative work, which has inspired the creation of this library.