Skip to content
View in the app

A better way to browse. Learn more.

Opusmodus

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Randomly pick a sublist (having a complex substructure)

Featured Replies

Forgive my ignorance, I am a LISP beginner.

I have used OM docs and resorted to gemini-LLM.

I simply cannot believe that there's not an easier solution for the problem I am looking for.

Please let me know if I am right and please help me extending my LISP skills - thanks.

Basically I have a list (level 0) which contains multiple sublists (level 1) which themselves hold on next level 2 two sublists as elements.

I want to randomly pick one of the lists on level 1.

I'd expect that the picked list is one level below the top and it resembles the original substructure below, i.e. holding two sublists as elements.

I have expected that OM's (rnd-pick ..) and (rnd-sample 1 ..) will do the job.

But if I have not completely messed it up they seem not to work as I expected.

With help on AI I somehow got it to work, but it seems a bit too complicated.

LISP aficionados / OM experts: any easier solution?

;;; Musical Motivation ----------------------------
;;;
;;; Combine LCCOTO with Triad Pair technique
;;;
;;; Process:
;;; We choose a parent scale
;;; From that scale we create all possible triads
;;; Next we find pairs of chords which have no overapping pitches
;;; These pairs have the property to cover the scale widely.
;;; Hence using them as cells for melodic material might be compositionally interesting.
;;;
;;; Below I intend to find these pairs and randomy pick one


;;; Setup ------------------------------------

;; Choose a Scale
(setf my-scale (expand-tonality '(c4 lydian)))
=> (c4 d4 e4 fs4 g4 a4 b4)

;; Get all triads of this scale and keep them all in one octave
(defun get-triad (x) (subseq x 0 3))
(setf triads-mat (ambitus-octaves 'c4 1 (mapcar 'get-triad
                         (pitch-melodize 
                          (mclist 
                           (gen-chord-series my-scale my-scale
                                             :width 30
                                             :type 3))))))
=> ((c4 e4 g4) 
    (d4 fs4 a4) 
    (e4 g4 b4) 
    (fs4 a4 c4) 
    (g4 b4 d4) 
    (a4 c4 e4) 
    (b4 d4 fs4))
;; Looks OK :-)

;; Find non-overlapping triads
(defun find-disjoint-pairs (list-of-lists)
  (loop for (sub1 . rest) on list-of-lists
        append (loop for sub2 in rest
                     when (null (intersection sub1 sub2))
                     collect (list sub1 sub2))))

(setf all-triad-pairs (find-disjoint-pairs triads-mat))
=> (((c4 e4 g4) (d4 fs4 a4)) 
    ((c4 e4 g4) (b4 d4 fs4)) 
    ((d4 fs4 a4) (e4 g4 b4)) 
    ((e4 g4 b4) (fs4 a4 c4)) 
    ((fs4 a4 c4) (g4 b4 d4)) 
    ((g4 b4 d4) (a4 c4 e4)) 
    ((a4 c4 e4) (b4 d4 fs4)))
;; Looks OK :-)
;; Is a list with Level 0, level 1, level 2
;; I want to pick on level 1
;; i.e. a valid solution would be: ((d4 fs4 a4) (e4 g4 b4)) 
;; thats 3rd row




;;; Issue start here --------------------------------

(setf one-triad-pair (rnd-pick all-triad-pairs))
=> (fs4 a4 c4)
;; Not what I'd expect; it should be a list with two sub-list-elements

(setf one-triad-pair (rnd-sample 1 all-triad-pairs))
=> ((fs4 a4 c4))
;; Again, not what I'd expect


;;; Solution , but a bit complex ---------------------
(setf one-triad-pair (nth 
                      (rnd-pick 
                       (gen-integer
                        (- (length all-triad-pairs) 1))) 
                      all-triad-pairs))
=> ((d4 fs4 a4) (e4 g4 b4))
;; Valid solution


;;; Question: Is this complicated solution really needed?
;;; Is there a OM function which does the sampling from outside to inside ?

I only had a quick look/read and built something like this: at level 0 you get a random pick of the pairs, at level 1 a sequence within a pair, and at level 2 a single value from a sequence of a pair. Was that what you meant?

For me, level 0 is not the whole list (i.e. the outermost parentheses), but rather all the pairs inside the outermost parentheses. If I do (length alist), I get 7 here, not 1. So there are 3 levels possible (0 to 2)

;;;
(setf alist '(((c4 e4 g4) (d4 fs4 a4)) 
             ((c4 e4 g4) (b4 d4 fs4)) 
             ((d4 fs4 a4) (e4 g4 b4)) 
             ((e4 g4 b4) (fs4 a4 c4)) 
             ((fs4 a4 c4) (g4 b4 d4)) 
             ((g4 b4 d4) (a4 c4 e4)) 
             ((a4 c4 e4) (b4 d4 fs4))))


(defun pick-from-level (alist level)
  (cond ((= level 0)
         (nth (random (length alist)) alist))
        ((= level 1)
         (rnd-pick (nth (random (length alist)) alist)))
        ((= level 2)
         (rnd-pick (flatten alist)))))
         

(pick-from-level alist 0)
=> ((g4 b4 d4) (a4 c4 e4))

(pick-from-level alist 1)
=> (c4 e4 g4)

(pick-from-level alist 2)
=> b4

If you want it nested—that is, pick from pick…—then you just need to nest the function. It will then always pick within the same level, either going down or up.

(pick-from-level 
 (pick-from-level alist 0) 0)
=> (fs4 a4 c4)

"It will then always pick within the same level,..." : PATH not LEVEL

  • Author

Thank you @AM , understood, your solution looks very elegant.

Create an account or sign in to comment


Copyright © 2014-2026 Opusmodus™ Ltd. All rights reserved.
Product features, specifications, system requirements and availability are subject to change without notice.
Opusmodus, the Opusmodus logo, and other Opusmodus trademarks are either registered trademarks or trademarks of Opusmodus Ltd.
All other trademarks contained herein are the property of their respective owners.

Powered by Invision Community

Important Information

Terms of Use Privacy Policy

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.