Fork me on GitHub
#meander
<
2020-05-01
>
keesterbrugge14:05:57

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? cheers

timothypratley22:05:22

Hi @U5309L9JP, 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}]

timothypratley22:05:01

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

keesterbrugge13:05:36

hi @U06S1EJPL, 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

nlessa14:05:28

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?

jimmy15:05:11

{: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.

💯 1
timothypratley22:05:44

Let the record state that today I tried to write a meander expression to match something with metadata 😛

timothypratley22:05:20

and that it worked find by doing (m/and ?thing (m/app meta ?meta))

👍 1
noprompt23:05:55

I’ve done this often enough myself and its come up before… maybe we should add it to the meander.epsilon?

timothypratley00:05:50

do you mean automatically try to match metadata? I guess there is an existing feature for sets which needs to be considered: ^{& ?rest-set} #{} but that seems like a pretty low collision chance! 🙂

timothypratley00:05:21

Argument for: Seems convenient, Argument against: Metadata is not considered in equality (is that important??? I don’t think so)