1
0
mirror of https://github.com/janet-lang/janet synced 2025-06-20 07:24:11 +00:00

Allow mapcat et al to accept multiple iterable arguments

#1159
This commit is contained in:
primo-ppcg 2023-05-25 18:12:38 +07:00
parent 909c906080
commit 672b705faf

View File

@ -923,67 +923,65 @@
(set k (next ind k))) (set k (next ind k)))
ret) ret)
(defn map (defmacro- map-aggregator
`Map a function over every value in a data structure and `Aggregation logic for various map functions.`
return an array of the results.` [maptype res val]
[f & inds] (case maptype
(def ninds (length inds)) :map ~(array/push ,res ,val)
(if (= 0 ninds) (error "expected at least 1 indexed collection")) :mapcat ~(array/concat ,res ,val)
(def res @[]) :keep ~(if (def y ,val) (array/push ,res y))
(def [i1 i2 i3 i4] inds) :count ~(if ,val (++ ,res))
:some ~(if (def y ,val) (do (set ,res y) (break)))
:all ~(if (def y ,val) nil (do (set ,res y) (break)))))
(defmacro- map-n
`Generates efficient map logic for a specific number of
indexed beyond the first.`
[n maptype res f ind inds]
~(do
(def ,(seq [k :range [0 n]] (symbol 'ind k)) ,inds)
,;(seq [k :range [0 n]] ~(var ,(symbol 'key k) nil))
(each x ,ind
,;(seq [k :range [0 n]]
~(if (= nil (set ,(symbol 'key k) (next ,(symbol 'ind k) ,(symbol 'key k)))) (break)))
(map-aggregator ,maptype ,res (,f x ,;(seq [k :range [0 n]] ~(in ,(symbol 'ind k) ,(symbol 'key k))))))))
(defmacro- map-template
[maptype res f ind inds]
~(do
(def ninds (length ,inds))
(case ninds (case ninds
1 (each x i1 (array/push res (f x))) 0 (each x ,ind (map-aggregator ,maptype ,res (,f x)))
2 (do ,;(kvs(tabseq [k :range [1 5]] k ~(map-n ,k ,maptype ,res ,f ,ind ,inds)))
(var k1 nil)
(var k2 nil)
(while true
(if (= nil (set k1 (next i1 k1))) (break))
(if (= nil (set k2 (next i2 k2))) (break))
(array/push res (f (in i1 k1) (in i2 k2)))))
3 (do
(var k1 nil)
(var k2 nil)
(var k3 nil)
(while true
(if (= nil (set k1 (next i1 k1))) (break))
(if (= nil (set k2 (next i2 k2))) (break))
(if (= nil (set k3 (next i3 k3))) (break))
(array/push res (f (in i1 k1) (in i2 k2) (in i3 k3)))))
4 (do
(var k1 nil)
(var k2 nil)
(var k3 nil)
(var k4 nil)
(while true
(if (= nil (set k1 (next i1 k1))) (break))
(if (= nil (set k2 (next i2 k2))) (break))
(if (= nil (set k3 (next i3 k3))) (break))
(if (= nil (set k4 (next i4 k4))) (break))
(array/push res (f (in i1 k1) (in i2 k2) (in i3 k3) (in i4 k4)))))
(do (do
(def iterkeys (array/new-filled ninds)) (def iter-keys (array/new-filled ninds))
(def call-buffer (array/new-filled ninds))
(var done false) (var done false)
(def call-buffer @[]) (each x ,ind
(while true
(forv i 0 ninds (forv i 0 ninds
(let [old-key (in iterkeys i) (let [old-key (in iter-keys i)
ii (in inds i) ii (in ,inds i)
new-key (next ii old-key)] new-key (next ii old-key)]
(if (= nil new-key) (if (= nil new-key)
(do (set done true) (break)) (do (set done true) (break))
(do (set (iterkeys i) new-key) (array/push call-buffer (in ii new-key)))))) (do (set (iter-keys i) new-key) (set (call-buffer i) (in ii new-key))))))
(if done (break)) (if done (break))
(array/push res (f ;call-buffer)) (map-aggregator ,maptype ,res (,f x ;call-buffer)))))))
(array/clear call-buffer))))
(defn map
`Map a function over every value in a data structure and
return an array of the results.`
[f ind & inds]
(def res @[])
(map-template :map res f ind inds)
res) res)
(defn mapcat (defn mapcat
``Map a function over every element in an array or tuple and ``Map a function over every element in an array or tuple and
use `array/concat` to concatenate the results.`` use `array/concat` to concatenate the results.``
[f ind] [f ind & inds]
(def res @[]) (def res @[])
(each x ind (map-template :mapcat res f ind inds)
(array/concat res (f x)))
res) res)
(defn filter (defn filter
@ -999,23 +997,19 @@
(defn count (defn count
``Count the number of items in `ind` for which `(pred item)` ``Count the number of items in `ind` for which `(pred item)`
is true.`` is true.``
[pred ind] [pred ind & inds]
(var counter 0) (var res 0)
(each item ind (map-template :count res pred ind inds)
(if (pred item) res)
(++ counter)))
counter)
(defn keep (defn keep
``Given a predicate `pred`, return a new array containing the truthy results ``Given a predicate `pred`, return a new array containing the truthy results
of applying `pred` to each element in the indexed collection `ind`. This is of applying `pred` to each element in the indexed collection `ind`. This is
different from `filter` which returns an array of the original elements where different from `filter` which returns an array of the original elements where
the predicate is truthy.`` the predicate is truthy.``
[pred ind] [pred ind & inds]
(def res @[]) (def res @[])
(each item ind (map-template :keep res pred ind inds)
(if-let [y (pred item)]
(array/push res y)))
res) res)
(defn range (defn range
@ -2090,21 +2084,21 @@
ret) ret)
(defn all (defn all
``Returns true if `(pred item)` returns a truthy value for every item in `xs`. ``Returns true if `(pred item)` is truthy for every item in `ind`.
Otherwise, returns the first falsey `(pred item)` result encountered. Otherwise, returns the first falsey result encountered.
Returns true if `xs` is empty.`` Returns true if `ind` is empty.``
[pred xs] [pred ind & inds]
(var ret true) (var res true)
(loop [x :in xs :while ret] (set ret (pred x))) (map-template :all res pred ind inds)
ret) res)
(defn some (defn some
``Returns nil if all `xs` are false or nil, otherwise returns the result of the ``Returns nil if `(pred item)` is false or nil for every item in `ind`.
first truthy predicate, `(pred x)`.`` Otherwise, returns the first truthy result encountered.``
[pred xs] [pred ind & inds]
(var ret nil) (var res nil)
(loop [x :in xs :while (not ret)] (if-let [y (pred x)] (set ret y))) (map-template :some res pred ind inds)
ret) res)
(defn deep-not= (defn deep-not=
``Like `not=`, but mutable types (arrays, tables, buffers) are considered ``Like `not=`, but mutable types (arrays, tables, buffers) are considered