Fork me on GitHub
#meander
<
2022-07-27
>
sergey16:07:44

let's say I want to collect lists of matching patterns and also a map key at a higher level in a nested map. ie. given the following map:

{:a {:client "foo"
     :items [{:x 1} 2 3]}
 :b {:client "bar"
     :items [{:x "q"} {:x "x"}]}}
I'd like to collect all values of maps with key :x under :items and also the value of :client that appears alongside those :items:
[["foo" [1] ["bar" ["q" "x"]]
What's a good way of doing this? Is it possible to generate that output with meander alone?

sergey16:07:56

I can get pretty close with the following:

(m/search {:a {:client "foo"
                 :items [{:x 1} 2 3]}
             :b {:client "bar"
                 :items [{:x "q"} {:x "x"}]}
             }
            (m/$ {:client ?c
                  :items (m/scan {:x !i})})
            [?c !i])
but it gives me pairs for each match rather than aggregating the !i values:
(["foo" [1]] ["bar" ["q"]] ["bar" ["x"]])

sergey16:07:05

(For more context, the map above is a simplified one; the actual map I want to extract the data from has a lot more levels of nesting under :items before the :x keys appear)

noprompt18:07:37

(defn f [m]
  (m/find m
    {:client ?client
     :items [(m/or {:x !x} _) ...]}
    [?client !x]))

(m/search {:a {:client "bar"
               :items [{:x "q"} {:x "x"}]}
           :b {:client "foo"
               :items [{:x 1} 2 3]}}
  {_ {:as ?v}} (f ?v))
;; =>
(["bar" ["q" "x"]] ["foo" [1]])

noprompt18:07:34

This would all be one pattern if epsilon had proper greediness.

sergey18:07:08

Gotcha - thanks for the context! I'll keep this in mind when I write queries in the future. The output without proper greediness is still very useful to me because it simplifies a lot of the map traversal logic that I'd otherwise have to write