Added pick and select for lists

Pick: (1 2 3 4)?4 or (1 2 3 4)?(3 2)
Select: (1 2 3 4)~2 or (1 2 3 4)~(2 3)
This commit is contained in:
2023-04-26 21:14:21 +03:00
parent cc3497fd29
commit 8f5d8adf48
6 changed files with 57 additions and 7 deletions

View File

@ -433,7 +433,7 @@ class RomanNumeral(Event):
pitch_classes: list = field(default=None, init=False)
inversions: int = field(default=None)
evaluated_chord: Chord = None
def set_notes(self, chord_notes: list[int]):
"""Set notes to roman numeral

View File

@ -2,6 +2,7 @@
from dataclasses import dataclass, field, replace
from itertools import product
from math import floor
import random
from types import LambdaType
from copy import deepcopy
import operator
@ -403,6 +404,47 @@ class ListOperation(Sequence):
return flattened_list
def _pick_from_list(left, right, options):
"""Pick random numbers from a list"""
if isinstance(left, Sequence):
left = _filter_operation(left, options)
if isinstance(right, Sequence):
right = _filter_operation(right, options)
if not isinstance(right, (list, Sequence)):
right = Sequence(values=[right])
result = []
for num in right.values:
for _ in range(num.get_value(options)):
result.append(random.choice(left.values))
return flatten(result)
def _select_from_list(left, right, options):
"""Select number of items from shuffled list"""
if isinstance(left, Sequence):
left = _filter_operation(left, options)
if isinstance(right, Sequence):
right = _filter_operation(right, options)
if not isinstance(right, (list, Sequence)):
right = Sequence(values=[right])
result = []
left = left.values
for num in right.values:
random.shuffle(left)
num = num.get_value(options)
new_list = [left[i % len(left)] for i in range(num)]
result += new_list
return flatten(result)
def _vertical_arpeggio(left, right, options):
"""Vertical arpeggio operation, eg. (135)@(q 1 2 021)"""
left = _filter_operation(left, options)
@ -537,8 +579,13 @@ class ListOperation(Sequence):
left = _vertical_arpeggio(left, right, options)
elif operation == "horizontal":
left = _horizontal_arpeggio(left, right, options)
if operation == "zip":
elif operation == "zip":
left = _cyclic_zip(left, right, options)
elif operation == "pick":
left = _pick_from_list(left, right, options)
elif operation == "select":
left = _select_from_list(left, right, options)
else:
left = _python_operations(left, right, options)
return left

View File

@ -62,7 +62,9 @@ OPERATORS = MappingProxyType({
">>": operator.irshift,
"@": "vertical",
"#": "horizontal",
"<>": "zip"
"<>": "zip",
"?": "pick",
"~": "select"
})

View File

@ -431,7 +431,7 @@ class ZiffersTransformer(Transformer):
def lisp_operation(self, items):
"""Parse lisp like list operation"""
op = items[0]
values = items[1:]
values = items[2]
return LispOperation(
operator=op,
values=values,

View File

@ -73,7 +73,6 @@ def zparse(expr: str, **opts) -> Ziffers:
parsed.init_opts(opts)
return parsed
# pylint: disable=invalid-name

View File

@ -56,8 +56,9 @@
right_op: list | number
// Operators that work only on lists: | << >>
list_operator: /(\||<<|>>|<>|#|@)(?=[(\d])/
// /(\||<<|>>|<>|#|@)(?=[(\d])/
// Common operators that works with numbers 3+5 3-5 etc.
operator: /([\+\-\*\/%\&])/
operator: /(\+|-|\*|\/|%|&|\?|~)/
// Euclidean cycles
// TODO: Support randomization etc.
@ -66,7 +67,8 @@
?euclid_operator: /<[0-9]+,[0-9]+(,[0-9])?>/
// Lisp like list operation
lisp_operation: "(" operator WS sequence ")"
lisp_operator: /([\+\-\*\/%\&])/
lisp_operation: "(" lisp_operator WS sequence ")"
// Subdivision
subdivision: "[" subitems "]"