Login
7 branches 0 tags
Ben (X13/Arch) Removed == since we have = e2eb8f1 2 years ago 1047 Commits
nujel / stdlib / collections / collection.nuj
;;; Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
;;; This project uses the MIT license, a copy should be included under /LICENSE
;;;
;;; A bunch of procedurs that work on all collections where the collection primitives are implemented

(defn sum (collection)
      "Return the sum of every value in collection

      collection: The collection to sum, can be a List, Vector or something else supported by reduce.

      The numeric sum of all the elements of collection"
      :cat :collection-operations

      (deftest :type-error (try car (sum 123)))
      (deftest 10 (+ (sum '(1 2 3)) (apply (fn (α) (+ 1 α)) '(3))))
      (deftest 15 (sum [1 2 3 4 5]))
      (deftest 6 (sum '(1 2 3)))

      (reduce collection + 0))

(defn every? (collection predicate?)
      "Returns whether predicate? is #t for every member of the collection

      collection: The collection to test, can be a List, Vector or something else supported by reduce.
      predicate?: A function that takes a single argument and returns a bool.

      Whether every invocation returned #t or not"
      :cat :collection-operations

      (deftest #t (every? '(1 2 3 4 5 6) int?))
      (deftest #f (every? '(1 2 3 4 5 6.0) int?))
      (deftest #t (every? '(1.0 6.0) float?))
      (deftest #f (every? '() float?))
      (deftest #t (every? [1 2 3 4 5 6] int?))
      (deftest #f (every? [1 2 3 4 5 6.0] int?))
      (deftest #t (every? [1.0 6.0] float?))
      (deftest #t (every? [] float?))

      (reduce collection (fn (a b) (and a (predicate? b))) #t))

(defn count (collection predicate?)
      "Count the number of items in the collection where predicate? is #t.
      If no predicate is provided, it will count the number of elements instead.

      collection: The collection to count in
      predicate?: Optional, a function that takes a single argument which is then called for every item.

      The number of times predicate? returned #t"
      :cat :collection-operations

      (deftest 0 (count #nil))
      (deftest 0 (count []))
      (deftest 1 (count '(1)))
      (deftest 1 (count [1]))
      (deftest 3 (count '(1 2 3)))
      (deftest 3 (count [1 2 3]))
      (deftest 2 (count [1 2 3 4] even?))
      (deftest 3 (count '(1 2 3 4 5 6) odd?))
      (deftest 3 (count '(1 2 3 4 5 6) even?))
      (deftest 6 (count '(1 2 3 4 5 6) int?))
      (deftest 0 (count '(1 2 3 4 5 6) float?))

      (if predicate?
          (reduce collection (fn (a b) (+ a (if (predicate? b) 1 0))) 0)
          (reduce collection (fn (a b) (+ a 1)) 0)))

(defn delete (l e)
      "Returns a filtered list l with all elements equal to e omitted"
      (filter l (fn (a) (not (= a e)))))

(defn remove (l p)
      "Returns a filtered list l with all elements where P equal true removed"
      (filter l (fn (a) (not (p a)))))

(def flatten (let*
               (defn flatten-λ (a b)
                     (cond ((collection? b ) (append (reduce b flatten-λ #nil) a))
                           (#t (cons b a))))
               (defn flatten (l)
                     "Flatten a collection of collections into a simple list"
                     (if-not (collection? l) l
                             (nreverse (reduce l flatten-λ #nil))))))

(defn join (l glue)
      "Join every element of α together into a string with GLUE inbetween"
      (when-not glue (set! glue ""))
      (when-not l (return ""))
      (reduce l (fn (a b) (if a (cat a glue b) b)) #nil))

(defn for-each (l f)
      "Runs F over every item in collection L"
      (def ret #nil)
      (doseq (i l ret)
             (set! ret (f i))))