# lisp / special divide - help needed

## Recommended Posts

LISP...
any solution? i want to DIVIDE a seq into sublists -> when it's asc into a list, "rest"  into single-listed values - thanx a lot for some help

```;;; input
(divide* '(14 12 3 13 15 8 4 10 17 2 16 0 1 6 7 5 11 9))

;;; output
=> ((14) (12) (3 13 15) (8) (4 10 17) (2 16) (0 1 6 7) (5 11) (9))```

##### Share on other sites

For a generic solution, you could use some function split-if that expects a Boolean function as argument comparing two consecutive pairs, and always splits a sublist if the Boolean function returns True. I don't have such a Lisp function at hand right now, but of an algorithm idea here is a similar Python function, only that this expects a Boolean function of a single argument only. If you port this function to Lisp, you could then generalise it by checking the number of arguments the given Boolean function expects, and it apply it always to the corresponding consecutive number of elements of xs.

```def split_if(fun, xs):
"""
Splits `xs` (list) into sublists based on a test. Starts a new sublist
at every element for which Boolean function `fun` returns true.

Examples
--------

>>> split_if(lambda x: x % 3 == 0, [0, 1, 2, 3, 4, 5])
[[0, 1, 2], [3, 4, 5]]

>>> split_if(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7])
[[1, 2], [3, 4, 5], [6, 7]]

NOTE:
Internally, `split_if` skips the first element of `xs`. So, if `fun` is
stateful, it should initialise its state using that first element.
For an example, see implementation of `format_api.split_into_sections`.
"""
result_list = []
start = 0
# Collect new list up to x whenever fun(x) == true, but not before first element
for index, x in enumerate(xs[1:]):
if fun(x):
result_list.append(xs[start:index+1])
start = index+1
if start == 0:
return [xs]
result_list.append(xs[start:])
return result_list```

Here is another approach as well with a Lisp function from my toolbox expecting a list of positions where to split the list. You could find those positions by iterating over conservative pairs of your list elements with the function positions-if listed below.

OK, none of this is a ready made solution, but all the necessary pieces are there  I need to head back to work now ....

Torsten

```(defun subseqs (sequence positions &optional end)
"Splits `sequence' into a list of subsequences split at `positions'. Each element in `positions' specifies a position at which a new sublist starts.

; (subseqs '(0 1 2 3 4 5 6) '(0 2 4))
=> ((0 1) (2 3) (4 5 6))

; (subseqs '(0 1 2 3 4 5 6) '(2 4 6) 5)
=> ((2 3) (4))

`positions' are implicitly sorted and positions beyond end are excluded.
"
(let* ((updated-pos (sort (if end
(remove-if #'(lambda (x) (>= x end))
positions)
positions)
#'<))
(full-pos (append updated-pos
(list (if end
end
(length sequence))))))
(mapcar #'(lambda (start end)
(subseq sequence start end))
(butlast full-pos)
(rest full-pos))
))

(defun positions-if (predicate sequence &key key (start 0))
"Like the Common Lisp function `position-if', but returns all positions in `sequence' that match `predicate'.

; (positions-if #'oddp '((1) (2) (3) (4)) :key #'car)
; => (0 2)"
(labels ((aux (predicate sequence &key key (start 0) accum)
(let ((pos (position-if predicate sequence :start start :key key)))
(if pos
(aux predicate sequence :start (1+ pos) :key key :accum (cons pos accum))
(reverse accum)))))
(aux predicate sequence :start start :key key)))

#|
;; comparison
(position-if #'oddp '((1) (2) (3) (4)) :key #'car)
|#

```

##### Share on other sites

good approaches, thank you!!

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×

• ### Similar Topics

• Revising some older code of my I noticed that the function length-divide changed its behaviour somewhat and became more likely to cause an error.

In a previous version, where the arguments count and divide where given separately, it was possible to set the count to some very high number, say, 1000, simply to mean that all notes the function can split (depending on its other arguments) will be split.

Meanwhile, the function have been revised to introduce control over intervals (thank you 🙂), but since then it seems it is not possible anymore to set an arbitrarily high count value anymore. For example, the following code now results in an error. I would prefer the previous behaviour, if only because it is more forgiving and stable.

(length-divide '(1000 2) '(q ab3 num1+leg c4 leg e ab3 leg g3 leg ab3 num1+leg c4 leg)) Error: The value ab3 is not of the expected type sequence.
In case it helps: my debugger tells me the functions gen-repeat and then maybe-section are called (perhaps within a nested function of length-divide* ?) with an argument sequence bound to ab3 (i.e. a plain pitch), and a call (length ab3) then causes this error.

Thank you!

Best,
Torsten

• The function LENGTH-DIVIDE and friends are a useful device for introducing some rhythmic variation to some material. However, when the processed sequence is a full OMN expression (see example below), then the added notes cause all other parameters to shift forward (additional parameters are added at the end by looping). For introducing only a slight variation to some existing material (e.g., motif) these functions are therefore not so useful, because this shift of all parameters to basically "fill" the new added notes with pitches etc. greatly change the varied material for a listener.
(length-divide 1 2 '(q f3 leg+m1 q ab3 leg e c4 leg bb3 leg ab3 leg g3))
Basically, this is the opposite situation of the situation addressed by swallowing. Swallowing (e.g., with GEN-SWALLOW and the swallow argument of many other functions) avoids the shift of parameters like pitch etc. that would result from removing notes and turning them into rests. For addressing the situation above properly we would need something like the opposite of swallowing, some way to fill in parameters like pitch etc. for new notes to avoid shifting existing notes. I hope my explanation makes sense and you can see why something like the opposite of swallowing would be useful for functions that add notes to some input material.

Now, the tricky question is of course, what parameters (pitch etc.) should be added in such cases. Musically useful and common in the classical literature would be, e.g., repeating the parameters (pitch etc.) of the predecessor note (though that might be a bit too simplistic and annoying at times) or somehow interpolating some pitch gap between the previous and next note with a little scale or arpeggio and only repeating the other parameters like articulations (resulting in some variation that is likely most similar to the input material, so it would be good to have that as an option).  If the pitch interval between the two original notes is too small to add some pitch in between for the new now (or as an option in general for variety), it would also be good  to add some ornamentation (e.g., using PITCH-ORNAMENT), but for a close similarity between the original material and the variation it would be best as an option to apply such ornamentation only to the newly added notes, not all notes. Of course, other options could also be useful for variations that vary the input material a bit more strongly, e.g., some random pitch for the new notes within certain interval bounds.

Does some function that kind of is the opposite of GEN-SWALLOW in that it adds parameters like pitches for subdivided rhythmic values (to avoid the shifting) sound like a good idea?

The idea with the interpolation of gaps could be implemented by turning the original duration values and pitches into some envelope and then reading that envelope with the new rhythmic values. So, that is rather strait forward. However, that would not allow for some ornamentation, because such algorithm would not recognise which notes are new that should be ornamented.

Any other idea perhaps? Thanks!

• What is the Lisp function for stopping playback (bound to the shortcut cmd-esc)?

... I could never add a custom keyboard shortcut to the Opusmodus text editor Hemlock (and I tried), but I just managed adding keyboard shortcuts and a menu for playing Opusmodus snippets and my polyphonic score format to Emacs (thanks to the fact that scores now can be displayed in a separate window). Only need some key for stopping playback as well.

(The main thing I will then miss when using Emacs as the Opusmodus IDE is the close integration of the document, but well, you cannot have everything 🙂  On the plus side, I have a more stable editor and in particular a very good debugger.)

Thanks!

Torsten
×

• Lessons