379 lines
10 KiB
Clojure
379 lines
10 KiB
Clojure
(ns Enum
|
|
"Elixir Enum module — eager operations on enumerables.
|
|
|
|
In CljElixir: (Enum/map coll f), (Enum/reduce coll acc f), etc.
|
|
Works on lists, maps, ranges, and any Enumerable.")
|
|
|
|
;; --- Mapping & Transformation ---
|
|
|
|
(defn map
|
|
"Returns a list with `f` applied to each element.
|
|
(Enum/map [1 2 3] (fn [x] (* x 2))) ;=> [2 4 6]"
|
|
[enumerable f])
|
|
|
|
(defn map-every
|
|
"Applies `f` to every `nth` element, starting with the first.
|
|
(Enum/map-every [1 2 3 4 5] 2 (fn [x] (* x 2))) ;=> [2 2 6 4 10]"
|
|
[enumerable nth f])
|
|
|
|
(defn flat-map
|
|
"Maps `f` over `enumerable` and flattens the result.
|
|
(Enum/flat-map [[1 2] [3 4]] (fn [x] x)) ;=> [1 2 3 4]"
|
|
[enumerable f])
|
|
|
|
(defn map-reduce
|
|
"Maps and reduces in one pass. Returns {mapped_list, acc}.
|
|
(Enum/map-reduce [1 2 3] 0 (fn [x acc] {(* x 2) (+ acc x)})) ;=> {[2 4 6] 6}"
|
|
[enumerable acc f])
|
|
|
|
(defn scan
|
|
"Returns a list of successive reduced values from the left.
|
|
(Enum/scan [1 2 3 4] (fn [x acc] (+ x acc))) ;=> [1 3 6 10]"
|
|
([enumerable f])
|
|
([enumerable acc f]))
|
|
|
|
;; --- Filtering ---
|
|
|
|
(defn filter
|
|
"Returns elements for which `f` returns a truthy value.
|
|
(Enum/filter [1 2 3 4] (fn [x] (> x 2))) ;=> [3 4]"
|
|
[enumerable f])
|
|
|
|
(defn reject
|
|
"Returns elements for which `f` returns a falsy value.
|
|
(Enum/reject [1 2 3 4] (fn [x] (> x 2))) ;=> [1 2]"
|
|
[enumerable f])
|
|
|
|
(defn uniq
|
|
"Returns unique elements, preserving order.
|
|
(Enum/uniq [1 2 1 3 2]) ;=> [1 2 3]"
|
|
[enumerable])
|
|
|
|
(defn uniq-by
|
|
"Returns elements unique by the result of `f`.
|
|
(Enum/uniq-by [{:x 1 :y 2} {:x 1 :y 3}] (fn [m] (:x m))) ;=> [{:x 1 :y 2}]"
|
|
[enumerable f])
|
|
|
|
(defn dedup
|
|
"Removes consecutive duplicate elements.
|
|
(Enum/dedup [1 1 2 2 3 1]) ;=> [1 2 3 1]"
|
|
[enumerable])
|
|
|
|
(defn dedup-by
|
|
"Removes consecutive elements where `f` returns the same value."
|
|
[enumerable f])
|
|
|
|
;; --- Reducing ---
|
|
|
|
(defn reduce
|
|
"Invokes `f` for each element with the accumulator.
|
|
(Enum/reduce [1 2 3] 0 (fn [x acc] (+ acc x))) ;=> 6
|
|
Note: Elixir callback order is (element, acc) not (acc, element)."
|
|
([enumerable f])
|
|
([enumerable acc f]))
|
|
|
|
(defn reduce-while
|
|
"Reduces while `f` returns {:cont, acc}. Halts on {:halt, acc}.
|
|
(Enum/reduce-while [1 2 3 4] 0 (fn [x acc] (if (< acc 5) {:cont (+ acc x)} {:halt acc})))"
|
|
[enumerable acc f])
|
|
|
|
(defn map-join
|
|
"Maps `f` over `enumerable` then joins results with `joiner`.
|
|
(Enum/map-join [1 2 3] \", \" (fn [x] (str x))) ;=> \"1, 2, 3\""
|
|
([enumerable f])
|
|
([enumerable joiner f]))
|
|
|
|
;; --- Sorting ---
|
|
|
|
(defn sort
|
|
"Sorts the enumerable. Uses Erlang term ordering or a custom comparator.
|
|
(Enum/sort [3 1 2]) ;=> [1 2 3]
|
|
(Enum/sort [3 1 2] (fn [a b] (> a b))) ;=> [3 2 1]"
|
|
([enumerable])
|
|
([enumerable sorter]))
|
|
|
|
(defn sort-by
|
|
"Sorts by the result of applying `mapper` to each element.
|
|
(Enum/sort-by [{:name \"b\"} {:name \"a\"}] (fn [x] (:name x))) ;=> [{:name \"a\"} {:name \"b\"}]"
|
|
([enumerable mapper])
|
|
([enumerable mapper sorter]))
|
|
|
|
;; --- Grouping & Partitioning ---
|
|
|
|
(defn group-by
|
|
"Groups elements by the result of `f`.
|
|
(Enum/group-by [\"ant\" \"bee\" \"ape\"] (fn [s] (String/at s 0)))
|
|
;=> %{\"a\" => [\"ant\" \"ape\"], \"b\" => [\"bee\"]}"
|
|
[enumerable f])
|
|
|
|
(defn chunk-by
|
|
"Splits into chunks where consecutive elements return the same value for `f`.
|
|
(Enum/chunk-by [1 1 2 2 3] (fn [x] x)) ;=> [[1 1] [2 2] [3]]"
|
|
[enumerable f])
|
|
|
|
(defn chunk-every
|
|
"Splits into chunks of `count` elements.
|
|
(Enum/chunk-every [1 2 3 4 5] 2) ;=> [[1 2] [3 4] [5]]"
|
|
([enumerable count])
|
|
([enumerable count step])
|
|
([enumerable count step leftover]))
|
|
|
|
(defn frequencies
|
|
"Returns a map with keys as unique elements and values as counts.
|
|
(Enum/frequencies [\"a\" \"b\" \"a\" \"c\" \"b\" \"a\"]) ;=> %{\"a\" => 3, \"b\" => 2, \"c\" => 1}"
|
|
[enumerable])
|
|
|
|
(defn split-with
|
|
"Splits into two lists: elements satisfying `f` and the rest.
|
|
(Enum/split-with [1 2 3 4] (fn [x] (< x 3))) ;=> {[1 2] [3 4]}"
|
|
[enumerable f])
|
|
|
|
(defn partition-by
|
|
"Splits when `f` returns a new value.
|
|
(Enum/partition-by [1 1 2 2 3] (fn [x] x)) ;=> [[1 1] [2 2] [3]]"
|
|
[enumerable f])
|
|
|
|
;; --- Lookup & Search ---
|
|
|
|
(defn find
|
|
"Returns the first element for which `f` returns truthy.
|
|
(Enum/find [1 2 3 4] (fn [x] (> x 2))) ;=> 3"
|
|
([enumerable f])
|
|
([enumerable default f]))
|
|
|
|
(defn find-index
|
|
"Returns the index of the first element for which `f` returns truthy.
|
|
(Enum/find-index [1 2 3] (fn [x] (= x 2))) ;=> 1"
|
|
[enumerable f])
|
|
|
|
(defn find-value
|
|
"Returns the first truthy return value of `f`.
|
|
(Enum/find-value [1 2 3] (fn [x] (if (> x 2) (* x 10) nil))) ;=> 30"
|
|
([enumerable f])
|
|
([enumerable default f]))
|
|
|
|
(defn member?
|
|
"Returns true if `element` exists in the enumerable.
|
|
(Enum/member? [1 2 3] 2) ;=> true"
|
|
[enumerable element])
|
|
|
|
(defn any?
|
|
"Returns true if any element satisfies `f` (or if any element is truthy).
|
|
(Enum/any? [false nil true]) ;=> true
|
|
(Enum/any? [1 2 3] (fn [x] (> x 2))) ;=> true"
|
|
([enumerable])
|
|
([enumerable f]))
|
|
|
|
(defn all?
|
|
"Returns true if all elements satisfy `f` (or all are truthy).
|
|
(Enum/all? [1 2 3] (fn [x] (> x 0))) ;=> true"
|
|
([enumerable])
|
|
([enumerable f]))
|
|
|
|
(defn count
|
|
"Returns the count of elements, optionally only those satisfying `f`.
|
|
(Enum/count [1 2 3]) ;=> 3
|
|
(Enum/count [1 2 3] (fn [x] (> x 1))) ;=> 2"
|
|
([enumerable])
|
|
([enumerable f]))
|
|
|
|
(defn empty?
|
|
"Returns true if the enumerable is empty.
|
|
(Enum/empty? []) ;=> true"
|
|
[enumerable])
|
|
|
|
;; --- Subsequences ---
|
|
|
|
(defn take
|
|
"Takes the first `amount` elements.
|
|
(Enum/take [1 2 3 4 5] 3) ;=> [1 2 3]"
|
|
[enumerable amount])
|
|
|
|
(defn take-while
|
|
"Takes elements while `f` returns truthy.
|
|
(Enum/take-while [1 2 3 4] (fn [x] (< x 3))) ;=> [1 2]"
|
|
[enumerable f])
|
|
|
|
(defn take-every
|
|
"Takes every `nth` element (0-indexed).
|
|
(Enum/take-every [1 2 3 4 5 6] 2) ;=> [1 3 5]"
|
|
[enumerable nth])
|
|
|
|
(defn drop
|
|
"Drops the first `amount` elements.
|
|
(Enum/drop [1 2 3 4 5] 2) ;=> [3 4 5]"
|
|
[enumerable amount])
|
|
|
|
(defn drop-while
|
|
"Drops elements while `f` returns truthy.
|
|
(Enum/drop-while [1 2 3 4] (fn [x] (< x 3))) ;=> [3 4]"
|
|
[enumerable f])
|
|
|
|
(defn slice
|
|
"Returns a subset of the enumerable.
|
|
(Enum/slice [1 2 3 4 5] 1 3) ;=> [2 3 4]
|
|
(Enum/slice [1 2 3 4 5] 1..3) ;=> [2 3 4]"
|
|
([enumerable index-range])
|
|
([enumerable start amount]))
|
|
|
|
(defn reverse
|
|
"Reverses the enumerable.
|
|
(Enum/reverse [1 2 3]) ;=> [3 2 1]"
|
|
([enumerable])
|
|
([enumerable tail]))
|
|
|
|
(defn shuffle
|
|
"Returns a list with elements in random order.
|
|
(Enum/shuffle [1 2 3 4 5]) ;=> [3 1 5 2 4]"
|
|
[enumerable])
|
|
|
|
;; --- Aggregation ---
|
|
|
|
(defn sum
|
|
"Returns the sum of all elements.
|
|
(Enum/sum [1 2 3]) ;=> 6"
|
|
[enumerable])
|
|
|
|
(defn product
|
|
"Returns the product of all elements.
|
|
(Enum/product [1 2 3 4]) ;=> 24"
|
|
[enumerable])
|
|
|
|
(defn min
|
|
"Returns the minimum element.
|
|
(Enum/min [3 1 2]) ;=> 1"
|
|
([enumerable])
|
|
([enumerable empty-fallback]))
|
|
|
|
(defn max
|
|
"Returns the maximum element.
|
|
(Enum/max [3 1 2]) ;=> 3"
|
|
([enumerable])
|
|
([enumerable empty-fallback]))
|
|
|
|
(defn min-by
|
|
"Returns the element for which `f` returns the smallest value.
|
|
(Enum/min-by [\"aaa\" \"b\" \"cc\"] (fn [s] (String/length s))) ;=> \"b\""
|
|
([enumerable f])
|
|
([enumerable f sorter]))
|
|
|
|
(defn max-by
|
|
"Returns the element for which `f` returns the largest value.
|
|
(Enum/max-by [\"aaa\" \"b\" \"cc\"] (fn [s] (String/length s))) ;=> \"aaa\""
|
|
([enumerable f])
|
|
([enumerable f sorter]))
|
|
|
|
(defn min-max
|
|
"Returns a tuple with the minimum and maximum elements.
|
|
(Enum/min-max [3 1 2]) ;=> {1 3}"
|
|
([enumerable])
|
|
([enumerable empty-fallback]))
|
|
|
|
(defn min-max-by
|
|
"Returns a tuple with the min/max elements by `f`."
|
|
([enumerable f])
|
|
([enumerable f sorter-or-empty]))
|
|
|
|
;; --- Joining & Conversion ---
|
|
|
|
(defn join
|
|
"Joins elements into a string with an optional separator.
|
|
(Enum/join [1 2 3] \", \") ;=> \"1, 2, 3\"
|
|
(Enum/join [1 2 3]) ;=> \"123\""
|
|
([enumerable])
|
|
([enumerable joiner]))
|
|
|
|
(defn into
|
|
"Inserts each element into a collectable.
|
|
(Enum/into [1 2 3] []) ;=> [1 2 3]
|
|
(Enum/into %{a: 1} %{b: 2}) ;=> %{a: 1, b: 2}
|
|
(Enum/into [1 2 3] [] (fn [x] (* x 2))) ;=> [2 4 6]"
|
|
([enumerable collectable])
|
|
([enumerable collectable transform]))
|
|
|
|
(defn to-list
|
|
"Converts an enumerable to a list.
|
|
(Enum/to-list (1..5)) ;=> [1 2 3 4 5]"
|
|
[enumerable])
|
|
|
|
(defn zip
|
|
"Zips corresponding elements from a finite collection of enumerables.
|
|
(Enum/zip [1 2 3] [:a :b :c]) ;=> [{1 :a} {2 :b} {3 :c}]"
|
|
([enumerables])
|
|
([enum1 enum2]))
|
|
|
|
(defn zip-with
|
|
"Zips with a merge function.
|
|
(Enum/zip-with [1 2 3] [4 5 6] (fn [a b] (+ a b))) ;=> [5 7 9]"
|
|
([enumerables zip-fun])
|
|
([enum1 enum2 zip-fun]))
|
|
|
|
(defn unzip
|
|
"Opposite of zip. Takes a list of two-element tuples and returns two lists.
|
|
(Enum/unzip [{1 :a} {2 :b}]) ;=> {[1 2] [:a :b]}"
|
|
[list])
|
|
|
|
(defn with-index
|
|
"Wraps each element in a tuple with its index.
|
|
(Enum/with-index [:a :b :c]) ;=> [{:a 0} {:b 1} {:c 2}]"
|
|
([enumerable])
|
|
([enumerable fun-or-offset]))
|
|
|
|
(defn flat-map-reduce
|
|
"Maps and reduces, emitting lists that get flattened. Returns {[flat_mapped], acc}."
|
|
[enumerable acc f])
|
|
|
|
;; --- Element Access ---
|
|
|
|
(defn at
|
|
"Returns the element at `index`. Returns `default` if out of bounds.
|
|
(Enum/at [1 2 3] 1) ;=> 2
|
|
(Enum/at [1 2 3] 5 :none) ;=> :none"
|
|
([enumerable index])
|
|
([enumerable index default]))
|
|
|
|
(defn fetch
|
|
"Returns {:ok element} or :error for index lookup.
|
|
(Enum/fetch [1 2 3] 1) ;=> {:ok 2}
|
|
(Enum/fetch [1 2 3] 5) ;=> :error"
|
|
[enumerable index])
|
|
|
|
(defn fetch!
|
|
"Returns the element at `index`. Raises if out of bounds.
|
|
(Enum/fetch! [1 2 3] 1) ;=> 2"
|
|
[enumerable index])
|
|
|
|
(defn random
|
|
"Returns a random element.
|
|
(Enum/random [1 2 3 4 5]) ;=> 3"
|
|
([enumerable])
|
|
([enumerable count]))
|
|
|
|
;; --- List Operations ---
|
|
|
|
(defn concat
|
|
"Concatenates enumerables.
|
|
(Enum/concat [1 2] [3 4]) ;=> [1 2 3 4]
|
|
(Enum/concat [[1 2] [3 4]]) ;=> [1 2 3 4]"
|
|
([enumerables])
|
|
([left right]))
|
|
|
|
(defn intersperse
|
|
"Inserts `separator` between each element.
|
|
(Enum/intersperse [1 2 3] 0) ;=> [1 0 2 0 3]"
|
|
[enumerable separator])
|
|
|
|
(defn each
|
|
"Invokes `f` for each element (side effects). Returns :ok.
|
|
(Enum/each [1 2 3] (fn [x] (IO/puts x)))"
|
|
[enumerable f])
|
|
|
|
(defn map-intersperse
|
|
"Maps and intersperses in one pass."
|
|
[enumerable separator mapper])
|
|
|
|
(defn split
|
|
"Splits into two lists at `count`.
|
|
(Enum/split [1 2 3 4 5] 3) ;=> {[1 2 3] [4 5]}"
|
|
[enumerable count])
|