git.fiddlerwoaroof.com
Raw Blame History
(defpackage :data-lens.t.transducers
  (:use :cl )
  (:export ))
(in-package :data-lens.t.transducers)

(5am:def-suite :data-lens.transducers)
(5am:in-suite :data-lens.transducers)

(5am:def-test mapping (:suite :data-lens.transducers)
  (5am:is (equal '(2 3 4)
                 (data-lens.transducers:transduce (data-lens.transducers:mapping '1+)
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3)))))

(5am:def-test mv-mapping (:suite :data-lens.transducers
                          :depends-on mapping)
  (5am:is (equal '((2 0) (3 1) (4 2))
                 (data-lens.transducers:transduce (data-lens.transducers:mv-mapping
                                                   (lambda (it)
                                                     (values (1+ it) (1- it))))
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3)))))

(5am:def-test mv-selecting (:suite :data-lens.transducers
                            :depends-on mapping)
  (5am:is (equal '(2 4)
                 (data-lens.transducers:transduce (data-lens.transducers:mv-selecting
                                                   (lambda (it)
                                                     (values (1+ it) (oddp it))))
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3))))
  (5am:is (equal '(a b)
                 (data-lens.transducers:transduce (data-lens.transducers:hash-table-select
                                                   (alexandria:alist-hash-table
                                                    '((1 . a)
                                                      (2 . b))))
                                                  'data-lens.transducers:list-builder
                                                  '(1 2)))))

(5am:def-test filtering (:suite :data-lens.transducers
                         :depends-on mapping)
  (5am:is (equal '(1 3)
                 (data-lens.transducers:transduce (data-lens.transducers:filtering 'oddp)
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3))))
  (5am:is (equal '(1 2)
                 (data-lens.transducers:transduce (data-lens.transducers:mv-filtering
                                                   'gethash (alexandria:alist-hash-table
                                                             '((1 . a)
                                                               (2 . b))))
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3)))))

(5am:def-test deduping (:suite :data-lens.transducers
                        :depends-on mapping)
  (5am:is (equal '(1 2 1 2 3 4 1)
                 (data-lens.transducers:transduce (data-lens.transducers:deduping)
                                                  'data-lens.transducers:list-builder
                                                  '(1 1 2 1 2 2 3 3 4 1))))
  (loop for first-number = (random 4)
        for second-number = (+ 5 (random 4))
        for third-number = (+ 10 (random 4))
        repeat 10 do
          (5am:is
           (equal (data-lens.transducers:transduce
                   (data-lens:• (data-lens.transducers:catting)
                                (data-lens.transducers:deduping))
                   'data-lens.transducers:list-builder
                   (list (data-lens.transducers:repeating* first-number :count (+ 1 (random 10)))
                         (data-lens.transducers:repeating* second-number :count (+ 1 (random 5)))
                         (data-lens.transducers:repeating* third-number :count (+ 1 (random 3)))))
                  (list first-number second-number third-number)))))

(5am:def-test compressing-runs (:suite :data-lens.transducers
                                :depends-on mapping)
  (5am:is (equal '(1 2 1 2 3 4 1)
                 (data-lens.transducers:transduce (data-lens.transducers:compressing-runs)
                                                  'data-lens.transducers:list-builder
                                                  '(1 1 2 1 2 2 3 3 4 1))))
  (loop for input = '(1) then (cons 1 input)
        repeat 5 do
          (5am:is (equal '(1)
                         (data-lens.transducers:transduce (data-lens.transducers:compressing-runs)
                                                          'data-lens.transducers:list-builder
                                                          input))))
  (loop for input = '(2 1) then (cons 2 input)
        repeat 5 do
          (5am:is (equal '(2 1)
                         (data-lens.transducers:transduce (data-lens.transducers:compressing-runs)
                                                          'data-lens.transducers:list-builder
                                                          input))))
  (loop for input = '(1 2) then (append input '(2))
        repeat 5 do
          (5am:is (equal '(1 2)
                         (data-lens.transducers:transduce (data-lens.transducers:compressing-runs)
                                                          'data-lens.transducers:list-builder
                                                          input))))

  (5am:is
   (equal '((1 2 2 2 3 3 3)
            (2 4 4 4 5 5 5)
            (3 6 6 6))
          (data-lens.transducers:transduce
           (data-lens.transducers:compressing-runs
            :test (lambda (a b) (eql (car a) (car b)))
            :combiner (lambda (a b)
                        (if a
                            (append a (cdr b))
                            b)))
           'data-lens.transducers:list-builder
           '((1 2 2 2) (1 3 3 3)
             (2 4 4 4) (2 5 5 5)
             (3 6 6 6))))))

(5am:def-test catting (:suite :data-lens.transducers
                       :depends-on mapping)
  (5am:is (equal '(1 1 2 1 2 2 3 3 4 1)
                 (data-lens.transducers:transduce (data-lens.transducers:catting)
                                                  'data-lens.transducers:list-builder
                                                  '((1 1) (2 1 2) (2) (3 3) (4 1))))))

(5am:def-test mapcatting (:suite :data-lens.transducers
                          :depends-on catting)
  (5am:is (equal '(1 1 2 1 2 2 3 3 4 1)
                 (data-lens.transducers:transduce (data-lens.transducers:mapcatting 'list)
                                                  'data-lens.transducers:list-builder
                                                  '(1 1 2 1 2 2 3 3 4 1))))
  (5am:is (equal '(0 0 1 0 1 2)
                 (data-lens.transducers:transduce (data-lens.transducers:mapcatting 'identity)
                                                  'data-lens.transducers:list-builder
                                                  (list (data-lens.transducers:iota :count 1)
                                                        (data-lens.transducers:iota :count 2)
                                                        (data-lens.transducers:iota :count 3))))))

(5am:def-test collecting (:suite :data-lens.transducers
                          :depends-on mapcatting)
  (5am:is (equal '(1 3 6 9 13 18 22 27 33 40)
                 (data-lens.transducers:transduce (data-lens:• (data-lens.transducers:taking 5)
                                                               (data-lens.transducers:mapcatting 'identity)
                                                               (data-lens.transducers::collecting '+))
                                                  'data-lens.transducers:list-builder
                                                  (loop for x from 1
                                                        repeat 4
                                                        collect
                                                        (data-lens.transducers:iota :start x
                                                                                    :count x))))))

(5am:def-test splitting (:suite :data-lens.transducers
                         :depends-on mapping)
  (5am:is (equal '((2 0) (3 1) (4 2))
                 (data-lens.transducers:transduce (data-lens.transducers:splitting '1+ '1-)
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3)))))

(5am:def-test transducer-composition (:suite :data-lens.transducers
                                      :depends-on (and filtering mapping))
  (5am:is (equal '(7)
                 (data-lens.transducers:transduce (data-lens:•
                                                   (data-lens.transducers:filtering #'oddp)
                                                   (data-lens.transducers:mapping
                                                    (lambda (x)
                                                      (* 2 x)))
                                                   (data-lens.transducers:mapping '1+)
                                                   (data-lens.transducers:dropping 1))
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3))))
  (5am:is (equal '(3 5)
                 (data-lens.transducers:transduce (data-lens:•
                                                   (data-lens.transducers:taking 2)
                                                   (data-lens.transducers:mapping
                                                    (lambda (x)
                                                      (* 2 x)))
                                                   (data-lens.transducers:mapping '1+))
                                                  'data-lens.transducers:list-builder
                                                  '(1 2 3)))))

(5am:def-test complicated (:suite :data-lens.transducers
                           :depends-on (and catting mapping filtering splitting
                                            transducer-composition))
  (let ((result (data-lens.transducers:transduce
                 (data-lens:•
                  (data-lens.transducers:catting)
                  (data-lens.transducers:mapping #'parse-integer)
                  (data-lens.transducers:filtering (complement #'evenp))
                  (data-lens.transducers:splitting (serapeum:op (* 2 _)) #'identity)
                  (data-lens.transducers:mapping (data-lens:transform-head #'1+))
                  (data-lens.transducers:taking 3))
                 'data-lens.transducers:hash-table-builder
                 '(("123" "234" "345" "454")
                   ("568" "490")
                   ("567" "213")))))
    (5am:is (equal '((247 . 123)
                     (691 . 345)
                     (1135 . 567))
                   (funcall (data-lens:• (data-lens:sorted '< :key 'car)
                                         (data-lens:sorted '< :key 'cdr))
                            (alexandria:hash-table-alist result))))))

(5am:def-test into (:suite :data-lens.transducers :depends-on mapping)
  (5am:is (equal '(0 1 2)
                 (data-lens.transducers:into '()
                                             (data-lens.transducers:taking 3)
                                             (data-lens.transducers:iota))))

  (5am:is (equal '(0 1 2)
                 (data-lens.transducers:into '(0 1 2)
                                             (data-lens.transducers:taking 0)
                                             (data-lens.transducers:iota))))

  (5am:is (equal '()
                 (data-lens.transducers:into '()
                                             (data-lens.transducers:taking 0)
                                             (data-lens.transducers:iota))))

  (5am:is (equal '()
                 (data-lens.transducers:into '()
                                             (data-lens.transducers:mapping #'identity)
                                             #())))

  (5am:is (equalp (alexandria:plist-hash-table '(:p 0 :l 1 :i 2 :s 3 :t 4))
                  (let ((count 0))
                    (data-lens.transducers:into (make-hash-table)
                                                (data-lens.transducers:mapping
                                                 (lambda (it)
                                                   (prog1 (list it count)
                                                     (incf count))))
                                                '(:p :l :i :s :t)))))
  (let ((l '((1 . 2)
             (2 . 3)
             (3 . 4))))
    (5am:is (equal l
                   (sort (alexandria:hash-table-alist
                          (data-lens.transducers:into (make-hash-table)
                                                      (data-lens.transducers:mapping 'identity)
                                                      (alexandria:alist-hash-table l)))
                         '<
                         :key 'car))))

  (loop for type in '(vector list)
        do (5am:is (equalp #(1 2 3 4 5 6)
                           (data-lens.transducers:into #(1 2 3)
                                                       (data-lens.transducers:mapping
                                                        (data-lens:inc 4))
                                                       (coerce #(0 1 2) type))))
           (5am:is (equal '(1 2 3 4 5 6)
                          (data-lens.transducers:into '(1 2 3)
                                                      (data-lens.transducers:mapping
                                                       (data-lens:inc 4))
                                                      (coerce #(0 1 2) type))))

           (5am:is (equal '(1 2 3 4 5 6)
                          (data-lens.transducers:into '(1 2 3)
                                                      (data-lens.transducers:mapping
                                                       (data-lens:inc 4))
                                                      (coerce #(0 1 2) type))))
           (5am:is (equal '(1 2 3 4 5 6)
                          (data-lens.transducers:into '(1 2 3)
                                                      (data-lens:•
                                                       (data-lens.transducers:taking 3)
                                                       (data-lens.transducers:mapping
                                                        (data-lens:inc 4)))
                                                      (data-lens.transducers:iota))))
           (5am:is (equalp #(1 2 3 4 5 6)
                           (data-lens.transducers:into #(1 2 3)
                                                       (data-lens:•
                                                        (data-lens.transducers:taking 3)
                                                        (data-lens.transducers:mapping
                                                         (data-lens:inc 4)))
                                                       (data-lens.transducers:iota))))))