# spellops
<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
## Developer Guide
Instead of writing this:
``` python
L(f_c(L(...).map(f_a).filter(f_b))).map(f_d)[0]
```
With `spellops`’s `pipe` operator, you can visually maintain the order
of execution (`f_a → filter(f_b) → f_c → f_d`) by writing this:
``` python
L(...).map(f_a).filter(f_b).pipe(f_c).map(f_d)[0]
```
And with `tee` operator, you can inspect and document your pipeline like
this:
``` python
(L(...) .tee('input data')
.map(f_a) .tee('apply f_a to individual elements')
.filter(f_b) .tee('filter by f_b')
.pipe(f_c) .tee('apply f_c to the whole list')
.map(f_d)[0] .tee('finally apply f_d to the resulting elements and returning first value')
)
```
And once you’re done, you can keep all of this in your production code:
``` python
def process(data,verbose=False):
s = dict(show=verbose)
return (L(data) .tee('input data', **s)
.map(f_a) .tee('apply f_a to individual elements', **s)
.filter(f_b) .tee('filter by f_b', **s)
.pipe(f_c) .tee('apply f_c to the whole list', **s)
.map(f_d) .tee('finally apply f_d to the resulting elements and returning first value', **s)
.unwrap() # Extract the element out of the list
)
```
Here are some examples:
## Import `L` and `spellops`
NOTE: order of import does not matters.
``` python
import spellops
from fastcore.foundation import L
```
### Fluent string manipulaiton
``` python
L(['a', 'b', 'c']).map(str.upper).pipe('->'.join, wrap=False)
```
'A->B->C'
Or using convenience mehtod `pipen` that stands for `pipe` with
`wrap=False` (no `wrap`):
``` python
L(['a', 'b', 'c']).map(str.upper).pipen('->'.join)
```
'A->B->C'
### Count how many elements are present in both sublists
``` python
(L([[1,2,3,2],[2,4,1]]) .tee('input')
.map(set) .tee('to set')
.starpipe(set.intersection) .tee('common elements')
.pipe(len) .tee('count elements')
.unwrap()
)
```
input
[[1, 2, 3, 2], [2, 4, 1]]
to set
[{1, 2, 3}, {1, 2, 4}]
common elements
[1, 2]
count elements
[2]
2
An alternative approach can be to pipe with `wrap=False`:
**NOTE:** In this case, you can’t use `tee` after the final `pipe`
operator because it no longer returns an `L` instance.
``` python
(L([[1,2,3,2],[2,4,1]]) .tee('input')
.map(set) .tee('to set')
.starpipe(set.intersection) .tee('common elements')
.pipe(len, wrap=False) # count elements
)
```
input
[[1, 2, 3, 2], [2, 4, 1]]
to set
[{1, 2, 3}, {1, 2, 4}]
common elements
[1, 2]
2
### Solve an AoC task
**SPOILER ALERT**: the following is a `speLL` to solve AoC 2024 part B.
**GOAL**: For each number in the left list, we need to count how many
times it appears in the right list, multiply these together, and sum all
results. This creates a “similarity score”, counting occurrences and
multiplying, that measures how frequently numbers from the left list
appear in the right list.
``` python
sample = '''3 4
4 3
2 5
1 3
3 9
3 3
'''
# This function will be "mapped" to individual elements
def to_int_tuple(a,b): return (int(a),int(b))
# this function acts on the whole list
def count_instances(As,Bs): return [(o,len([t for t in Bs if t==o])) for o in As]
from math import prod
(L(sample.splitlines())
.map(str.split) .tee('input data')
.starmap(to_int_tuple) .tee('int to tuples')
.zip(cycled=True) .tee('tuple of lists')
.starpipe(count_instances) .tee('apply count_instances to the "whole list"')
.map(prod) .tee('multiply tuple elements')
.sum()
)
```
input data
[['3', '4'], ['4', '3'], ['2', '5'], ['1', '3'], ['3', '9'], ['3', '3']]
int to tuples
[(3, 4), (4, 3), (2, 5), (1, 3), (3, 9), (3, 3)]
tuple of lists
[(3, 4, 2, 1, 3, 3), (4, 3, 5, 3, 9, 3)]
apply count_instances to the "whole list"
[(3, 3), (4, 1), (2, 0), (1, 0), (3, 3), (3, 3)]
multiply tuple elements
[9, 4, 0, 0, 9, 9]
31
### Visually inspect images transformations:
``` python
import matplotlib.pyplot as plt
import numpy as np
def plot_images(x:L, msg):
N = len(x)
plt.figure(figsize=(4*N,4))
for i,o in enumerate(x):
plt.subplot(1,N,i+1)
plt.imshow(o)
plt.title(f'Image: {i}')
plt.suptitle(msg)
(L([[[0,0,0],[1,1,1],[0,0,0]],[[1,0,0],[0,1,0],[0,0,1]]]) .tee('Input images',f=plot_images)
.map(lambda x: np.rot90(x,k=1)) .tee('Rotate 90 degree',f=plot_images)
)
```
(#2) [array([[0, 1, 0],
[0, 1, 0],
[0, 1, 0]]),array([[0, 0, 1],
[0, 1, 0],
[1, 0, 0]])]
![](index_files/figure-commonmark/cell-8-output-2.png)
![](index_files/figure-commonmark/cell-8-output-3.png)
### Install spellops in Development mode
``` sh
# make sure spellops package is installed in development mode
$ pip install -e .
# make changes under nbs/ directory
# ...
# compile to have changes apply to spellops
$ nbdev_prepare
```
## Usage
### Installation
Install latest from the GitHub
[repository](https://github.com/artste/spellops):
``` sh
$ pip install git+https://github.com/artste/spellops.git
```
or from [pypi](https://pypi.org/project/spellops/)
``` sh
$ pip install spellops
```
Raw data
{
"_id": null,
"home_page": "https://github.com/artste/spellops",
"name": "spellops",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "nbdev jupyter notebook python",
"author": "Stefano Giomo",
"author_email": "artste@users.noreply.github.com",
"download_url": "https://files.pythonhosted.org/packages/17/2d/37796f763d1c472d1b31e0b0c93a8ba4fd68c9dec7949e214ec2892b5f5e/spellops-0.0.1.tar.gz",
"platform": null,
"description": "# spellops\n\n\n<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->\n\n## Developer Guide\n\nInstead of writing this:\n\n``` python\nL(f_c(L(...).map(f_a).filter(f_b))).map(f_d)[0]\n```\n\nWith `spellops`\u2019s `pipe` operator, you can visually maintain the order\nof execution (`f_a \u2192 filter(f_b) \u2192 f_c \u2192 f_d`) by writing this:\n\n``` python\nL(...).map(f_a).filter(f_b).pipe(f_c).map(f_d)[0]\n```\n\nAnd with `tee` operator, you can inspect and document your pipeline like\nthis:\n\n``` python\n(L(...) .tee('input data')\n .map(f_a) .tee('apply f_a to individual elements')\n .filter(f_b) .tee('filter by f_b')\n .pipe(f_c) .tee('apply f_c to the whole list')\n .map(f_d)[0] .tee('finally apply f_d to the resulting elements and returning first value')\n)\n```\n\nAnd once you\u2019re done, you can keep all of this in your production code:\n\n``` python\ndef process(data,verbose=False):\n s = dict(show=verbose)\n return (L(data) .tee('input data', **s)\n .map(f_a) .tee('apply f_a to individual elements', **s)\n .filter(f_b) .tee('filter by f_b', **s)\n .pipe(f_c) .tee('apply f_c to the whole list', **s)\n .map(f_d) .tee('finally apply f_d to the resulting elements and returning first value', **s)\n .unwrap() # Extract the element out of the list\n )\n```\n\nHere are some examples:\n\n## Import `L` and `spellops`\n\nNOTE: order of import does not matters.\n\n``` python\nimport spellops\nfrom fastcore.foundation import L\n```\n\n### Fluent string manipulaiton\n\n``` python\nL(['a', 'b', 'c']).map(str.upper).pipe('->'.join, wrap=False)\n```\n\n 'A->B->C'\n\nOr using convenience mehtod `pipen` that stands for `pipe` with\n`wrap=False` (no `wrap`):\n\n``` python\nL(['a', 'b', 'c']).map(str.upper).pipen('->'.join)\n```\n\n 'A->B->C'\n\n### Count how many elements are present in both sublists\n\n``` python\n(L([[1,2,3,2],[2,4,1]]) .tee('input')\n .map(set) .tee('to set')\n .starpipe(set.intersection) .tee('common elements')\n .pipe(len) .tee('count elements')\n .unwrap()\n)\n```\n\n input\n [[1, 2, 3, 2], [2, 4, 1]]\n to set\n [{1, 2, 3}, {1, 2, 4}]\n common elements\n [1, 2]\n count elements\n [2]\n\n 2\n\nAn alternative approach can be to pipe with `wrap=False`:\n\n**NOTE:** In this case, you can\u2019t use `tee` after the final `pipe`\noperator because it no longer returns an `L` instance.\n\n``` python\n(L([[1,2,3,2],[2,4,1]]) .tee('input')\n .map(set) .tee('to set')\n .starpipe(set.intersection) .tee('common elements')\n .pipe(len, wrap=False) # count elements\n)\n```\n\n input\n [[1, 2, 3, 2], [2, 4, 1]]\n to set\n [{1, 2, 3}, {1, 2, 4}]\n common elements\n [1, 2]\n\n 2\n\n### Solve an AoC task\n\n**SPOILER ALERT**: the following is a `speLL` to solve AoC 2024 part B.\n\n**GOAL**: For each number in the left list, we need to count how many\ntimes it appears in the right list, multiply these together, and sum all\nresults. This creates a \u201csimilarity score\u201d, counting occurrences and\nmultiplying, that measures how frequently numbers from the left list\nappear in the right list.\n\n``` python\nsample = '''3 4\n4 3\n2 5\n1 3\n3 9\n3 3\n'''\n\n# This function will be \"mapped\" to individual elements\ndef to_int_tuple(a,b): return (int(a),int(b))\n\n# this function acts on the whole list\ndef count_instances(As,Bs): return [(o,len([t for t in Bs if t==o])) for o in As]\n\nfrom math import prod\n(L(sample.splitlines())\n .map(str.split) .tee('input data')\n .starmap(to_int_tuple) .tee('int to tuples')\n .zip(cycled=True) .tee('tuple of lists')\n .starpipe(count_instances) .tee('apply count_instances to the \"whole list\"')\n .map(prod) .tee('multiply tuple elements')\n .sum()\n )\n```\n\n input data\n [['3', '4'], ['4', '3'], ['2', '5'], ['1', '3'], ['3', '9'], ['3', '3']]\n int to tuples\n [(3, 4), (4, 3), (2, 5), (1, 3), (3, 9), (3, 3)]\n tuple of lists\n [(3, 4, 2, 1, 3, 3), (4, 3, 5, 3, 9, 3)]\n apply count_instances to the \"whole list\"\n [(3, 3), (4, 1), (2, 0), (1, 0), (3, 3), (3, 3)]\n multiply tuple elements\n [9, 4, 0, 0, 9, 9]\n\n 31\n\n### Visually inspect images transformations:\n\n``` python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\ndef plot_images(x:L, msg):\n N = len(x)\n plt.figure(figsize=(4*N,4))\n for i,o in enumerate(x):\n plt.subplot(1,N,i+1)\n plt.imshow(o)\n plt.title(f'Image: {i}')\n plt.suptitle(msg)\n\n(L([[[0,0,0],[1,1,1],[0,0,0]],[[1,0,0],[0,1,0],[0,0,1]]]) .tee('Input images',f=plot_images)\n .map(lambda x: np.rot90(x,k=1)) .tee('Rotate 90 degree',f=plot_images)\n)\n```\n\n (#2) [array([[0, 1, 0],\n [0, 1, 0],\n [0, 1, 0]]),array([[0, 0, 1],\n [0, 1, 0],\n [1, 0, 0]])]\n\n![](index_files/figure-commonmark/cell-8-output-2.png)\n\n![](index_files/figure-commonmark/cell-8-output-3.png)\n\n### Install spellops in Development mode\n\n``` sh\n# make sure spellops package is installed in development mode\n$ pip install -e .\n\n# make changes under nbs/ directory\n# ...\n\n# compile to have changes apply to spellops\n$ nbdev_prepare\n```\n\n## Usage\n\n### Installation\n\nInstall latest from the GitHub\n[repository](https://github.com/artste/spellops):\n\n``` sh\n$ pip install git+https://github.com/artste/spellops.git\n```\n\nor from [pypi](https://pypi.org/project/spellops/)\n\n``` sh\n$ pip install spellops\n```\n",
"bugtrack_url": null,
"license": "Apache Software License 2.0",
"summary": "Harness the power of speLL with spellops to write clean and readable pipelines.",
"version": "0.0.1",
"project_urls": {
"Homepage": "https://github.com/artste/spellops"
},
"split_keywords": [
"nbdev",
"jupyter",
"notebook",
"python"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ff49d530041d85bb4e408ed532c88a111715c8527eef53810a91883f0d204514",
"md5": "294806705f00b9a511eadd5d5fa3236c",
"sha256": "174692d2c5ad9f27ac3ee812590e1d6794b216a10d9bab6007764e7bd8edf8a8"
},
"downloads": -1,
"filename": "spellops-0.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "294806705f00b9a511eadd5d5fa3236c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 5489,
"upload_time": "2025-01-06T12:35:52",
"upload_time_iso_8601": "2025-01-06T12:35:52.874649Z",
"url": "https://files.pythonhosted.org/packages/ff/49/d530041d85bb4e408ed532c88a111715c8527eef53810a91883f0d204514/spellops-0.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "172d37796f763d1c472d1b31e0b0c93a8ba4fd68c9dec7949e214ec2892b5f5e",
"md5": "205e395833a61634b112a086027d1386",
"sha256": "d0064533e52751cb721c8a627614e3a0062b53137fda460795af800c2888c7f7"
},
"downloads": -1,
"filename": "spellops-0.0.1.tar.gz",
"has_sig": false,
"md5_digest": "205e395833a61634b112a086027d1386",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 6817,
"upload_time": "2025-01-06T12:35:57",
"upload_time_iso_8601": "2025-01-06T12:35:57.766495Z",
"url": "https://files.pythonhosted.org/packages/17/2d/37796f763d1c472d1b31e0b0c93a8ba4fd68c9dec7949e214ec2892b5f5e/spellops-0.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-06 12:35:57",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "artste",
"github_project": "spellops",
"github_not_found": true,
"lcname": "spellops"
}