Arc Forumnew | comments | leaders | submitlogin
3 points by tokipin 5760 days ago | link | parent

here's my take

  (def wrand args
      (withs (weights (sort (compare > car) (pair args))
              unit   (/ 1.0 (reduce + (map car weights))))
          
         (ccc (fn (return)
             (with (acc 0 r (rand))
  
                 (each (weight val) weights
                     (= acc (+ acc weight))
                     (if (< r (* acc unit))
                         (return val))))))))
i think the sort might be unnecessary but my mind isn't functioning atm


1 point by skenney26 5759 days ago | link

Shouldn't there be a simple, elegant solution to this problem that doesn't necessitate using ccc and return? Maybe I'm resistant to using continuations because I'm still coming to grips with understanding them... but there's alot of code in arc.arc and only one call to ccc.

-----

1 point by rkts 5759 days ago | link

You can write a tail-recursive version of tokipin's code pretty easily. Personally though I think this could be an addition to the "examples of LOOP" thread from a while back.

  (defun wrandf (xs weights)
    (loop with r = (random (apply #'+ weights))
          for x in xs
          for w in weights
          for cw = w then (+ cw w)
          when (> cw r) return x))

  ; assumes pair
  (defmacro wrand (&rest args)
    `(funcall
       (wrandf
         (list ,@(mapcar (lambda (x) `(lambda () ,(cadr x))) (pair args)))
         (list ,@(mapcar #'car (pair args))))))

-----

1 point by almkglor 5760 days ago | link

The sort is indeed unnecessary, and the solution above is indeed the classic solution to the weighted random choice

-----