Hi everybody, I'm really excited by the potential of meander and I'm trying to figure out if I can make my code more transparent by using meander for data science.
I'm getting data in the shape of [{:a [1 2]}]
and I need to transform it such that it becomes [{:a 1 :idx-row 0 :idx-vec 0} {:a 2 :idx-row 0 :idx-vec 1}]
which I can plot with vega-lite. So I need to unpack and index the elements of the vectors and add row indices (`:idx-row`).
I've written the unpack-and-index-vec-from-seq-of-map
function to get it in the right shape, but I'd like to do this with meander.
(defn unpack-and-index-vec-from-seq-of-map [vec-key seq-of-maps]
(->> seq-of-maps
(map-indexed (fn [idx-row m] (assoc m :idx-row idx-row)))
(map (fn [row]
(map-indexed
(fn [idx-vec vec-element]
(assoc row vec-key vec-element :idx-vec idx-vec))
(get row vec-key))))
(apply concat)))
(def test-data [{:b 2 :a [2 3]} {:b 3 :a [4 5]}])
(unpack-and-index-vec-from-seq-of-map :a test-data)
;; =>
;; ({:b 2, :a 2, :idx-row 0, :idx-vec 0}
;; {:b 2, :a 3, :idx-row 0, :idx-vec 1}
;; {:b 3, :a 4, :idx-row 1, :idx-vec 0}
;; {:b 3, :a 5, :idx-row 1, :idx-vec 1})
I'm a bit overwhelmed with all the possibilities I have in meander. Can you help me figure out how this would work?
cheershi @timothypratley, Thanks for helping me out. Although I'm happy to see it's possible with meander, I think this might not be a good use case for clarifying the transformation with meander. Especially so, since the real case actually has a vector of size n
in each map with key :a
, instead of size 2.
Cheers
Hi @noprompt! Another case I am dealing and not understanding if I am missing some subtlety is one like below (I shortened the real use for easiness)
((ms/bottom-up
(ms/attempt
(ms/rewrite
{:type (me/pred keyword? *acc) :constraints ?constraints :args *args}
?constraints
{:accumulator *acc :result-binding *result-binding :from ?constraints-ac} ?constraints-ac)))
'({:type :some/keyword,
:constraints [(= item ?item) (= tipo-contrato ?tipo-contrato) (= descontados ?descontados) (= mapa ?mapa)],
:args [something]}))
=> ([(= item ?item) (= tipo-contrato ?tipo-contrato) (= descontados ?descontados) (= mapa ?mapa)])
But if I invert the order of the clauses
((ms/bottom-up
(ms/attempt
(ms/rewrite
{:accumulator *acc :result-binding *result-binding :from ?constraints-ac} ?constraints-ac
{:type (me/pred keyword? *acc) :constraints ?constraints :args *args}
?constraints)))
'({:type :some/keyword,
:constraints [(= item ?item) (= tipo-contrato ?tipo-contrato) (= descontados ?descontados) (= mapa ?mapa)],
:args [something]}))
=> (nil)
What would be the reason for (nil) in the inversion of the order of the clauses?{:accumulator *acc :result-binding *result-binding :from ?constraints-ac}
will match any map even if it doesn't have those keys. You can use (m/some ?constraints-ac)
to make sure the key really exists.
Hi @keesterbrugge, Here is one way:
(m/rewrite [{:b 2 :a [2 3]} {:b 3 :a [4 5]}]
(m/and
[{:a [!x !y] & (m/and !m1 !m2)} ..?n]
(m/let [((m/and !ns1 !ns2) ...) (range ?n)]))
[{:a !x
:idx-row !ns1
:idx-vec 0
& !m1}
{:a !y
:idx-row !ns2
:idx-vec 1
& !m2}
...])
=>
[{:b 2, :a 2, :idx-row 0, :idx-vec 0}
{:b 2, :a 3, :idx-row 0, :idx-vec 1}
{:b 3, :a 4, :idx-row 1, :idx-vec 0}
{:b 3, :a 5, :idx-row 1, :idx-vec 1}]
Unfortunately there are two confusing bits about my solution:
1. Iām using an and
trick to create 2 memory variables !m1 and !m2 because we intend to substitute them twice
2. Using let
to create 2 index variables
Let the record state that today I tried to write a meander expression to match something with metadata š
and that it worked find by doing (m/and ?thing (m/app meta ?meta))