How to explore Java methods through REPL - clojure

I am playing with Clojure and Java Interop and I came up with the following to inspect the methods of some instance:
(defn methods-of [instance & [string]]
{:pre [(nil? instance)]}
(filter #(re-find (re-pattern (or string #".*")) %) (map #(.getName %) (-> instance class .getMethods))))
But I was wondering, given that this is a very practical way to get this info from REPL, if there was some library out there to achieve this (and more).

Clojure comes with a namespace that helps with reflection: clojure.reflect. The main function to use is clojure.reflect/reflect.
user> (require '[clojure.reflect :as reflect])
nil
user> (clojure.pprint/pprint (reflect/reflect (java.util.Date.)))
{:bases
#{java.io.Serializable java.lang.Comparable java.lang.Object
java.lang.Cloneable},
:flags #{:public},
:members
#{{:name getSeconds,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name serialVersionUID,
:type long,
:declaring-class java.util.Date,
:flags #{:private :static :final}}
{:name getCalendarDate,
:return-type sun.util.calendar.BaseCalendar$Date,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:private :final}}
{:name after,
:return-type boolean,
:declaring-class java.util.Date,
:parameter-types [java.util.Date],
:exception-types [],
:flags #{:public}}
{:name hashCode,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name wtb,
:type java.lang.String<>,
:declaring-class java.util.Date,
:flags #{:private :static :final}}
{:name setMonth,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:public}}
{:name getMonth,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name getCalendarSystem,
:return-type sun.util.calendar.BaseCalendar,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:private :static :final}}
{:name fastTime,
:type long,
:declaring-class java.util.Date,
:flags #{:transient :private}}
{:name defaultCenturyStart,
:type int,
:declaring-class java.util.Date,
:flags #{:private :static}}
{:name writeObject,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [java.io.ObjectOutputStream],
:exception-types [java.io.IOException],
:flags #{:private}}
{:name getMillisOf,
:return-type long,
:declaring-class java.util.Date,
:parameter-types [java.util.Date],
:exception-types [],
:flags #{:static :final}}
{:name getMinutes,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name ttb,
:type int<>,
:declaring-class java.util.Date,
:flags #{:private :static :final}}
{:name setDate,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:public}}
{:name setSeconds,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:public}}
{:name java.util.Date,
:declaring-class java.util.Date,
:parameter-types [long],
:exception-types [],
:flags #{:public}}
{:name getTimeImpl,
:return-type long,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:private :final}}
{:name setYear,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:public}}
{:name normalize,
:return-type sun.util.calendar.BaseCalendar$Date,
:declaring-class java.util.Date,
:parameter-types [sun.util.calendar.BaseCalendar$Date],
:exception-types [],
:flags #{:private :final}}
{:name getHours,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name getYear,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name java.util.Date,
:declaring-class java.util.Date,
:parameter-types [int int int int int int],
:exception-types [],
:flags #{:public}}
{:name java.util.Date,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name UTC,
:return-type long,
:declaring-class java.util.Date,
:parameter-types [int int int int int int],
:exception-types [],
:flags #{:static :public}}
{:name getTime,
:return-type long,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name getJulianCalendar,
:return-type sun.util.calendar.BaseCalendar,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:synchronized :private :static :final}}
{:name getCalendarSystem,
:return-type sun.util.calendar.BaseCalendar,
:declaring-class java.util.Date,
:parameter-types [sun.util.calendar.BaseCalendar$Date],
:exception-types [],
:flags #{:private :static :final}}
{:name setTime,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [long],
:exception-types [],
:flags #{:public}}
{:name setMinutes,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:public}}
{:name cdate,
:type sun.util.calendar.BaseCalendar$Date,
:declaring-class java.util.Date,
:flags #{:transient :private}}
{:name getDay,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name toString,
:return-type java.lang.String,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name java.util.Date,
:declaring-class java.util.Date,
:parameter-types [int int int int int],
:exception-types [],
:flags #{:public}}
{:name java.util.Date,
:declaring-class java.util.Date,
:parameter-types [int int int],
:exception-types [],
:flags #{:public}}
{:name toInstant,
:return-type java.time.Instant,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name clone,
:return-type java.lang.Object,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name from,
:return-type java.util.Date,
:declaring-class java.util.Date,
:parameter-types [java.time.Instant],
:exception-types [],
:flags #{:static :public}}
{:name compareTo,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [java.util.Date],
:exception-types [],
:flags #{:public}}
{:name toLocaleString,
:return-type java.lang.String,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name convertToAbbr,
:return-type java.lang.StringBuilder,
:declaring-class java.util.Date,
:parameter-types [java.lang.StringBuilder java.lang.String],
:exception-types [],
:flags #{:private :static :final}}
{:name getTimezoneOffset,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name toGMTString,
:return-type java.lang.String,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name normalize,
:return-type sun.util.calendar.BaseCalendar$Date,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:private :final}}
{:name parse,
:return-type long,
:declaring-class java.util.Date,
:parameter-types [java.lang.String],
:exception-types [],
:flags #{:static :public}}
{:name jcal,
:type sun.util.calendar.BaseCalendar,
:declaring-class java.util.Date,
:flags #{:private :static}}
{:name gcal,
:type sun.util.calendar.BaseCalendar,
:declaring-class java.util.Date,
:flags #{:private :static :final}}
{:name before,
:return-type boolean,
:declaring-class java.util.Date,
:parameter-types [java.util.Date],
:exception-types [],
:flags #{:public}}
{:name compareTo,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [java.lang.Object],
:exception-types [],
:flags #{:synthetic :bridge :public}}
{:name getDate,
:return-type int,
:declaring-class java.util.Date,
:parameter-types [],
:exception-types [],
:flags #{:public}}
{:name readObject,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [java.io.ObjectInputStream],
:exception-types
[java.io.IOException java.lang.ClassNotFoundException],
:flags #{:private}}
{:name setHours,
:return-type void,
:declaring-class java.util.Date,
:parameter-types [int],
:exception-types [],
:flags #{:public}}
{:name getCalendarSystem,
:return-type sun.util.calendar.BaseCalendar,
:declaring-class java.util.Date,
:parameter-types [long],
:exception-types [],
:flags #{:private :static :final}}
{:name equals,
:return-type boolean,
:declaring-class java.util.Date,
:parameter-types [java.lang.Object],
:exception-types [],
:flags #{:public}}
{:name java.util.Date,
:declaring-class java.util.Date,
:parameter-types [java.lang.String],
:exception-types [],
:flags #{:public}}}}
nil
user>
Sometimes, it's easier to use bean to see the various fields present.
user> (clojure.pprint/pprint (bean (java.util.Date.)))
{:seconds 9,
:date 30,
:class java.util.Date,
:minutes 13,
:hours 8,
:year 114,
:timezoneOffset 420,
:month 7,
:day 6,
:time 1409411589031}
nil
Using reflect/reflect to list all method names (as you were doing in your example):
user> (->> (reflect/reflect (java.util.Date.)) :members (filter :return-type) (map :name))
(getSeconds getCalendarDate after hashCode setMonth getMonth getCalendarSystem writeObject getMillisOf getMinutes setDate setSeconds getTimeImpl setYear normalize getHours getYear UTC getTime getJulianCalendar getCalendarSystem setTime setMinutes getDay toString toInstant clone from compareTo toLocaleString convertToAbbr getTimezoneOffset toGMTString normalize parse before compareTo getDate readObject setHours getCalendarSystem equals)

Have a look at iroh.
> (.? String #"^conta") ;; grep all fields/methods that start with conta
(#[contains :: (java.lang.String, java.lang.CharSequence) -> boolean])
> (.? String #"^con" :name) ;; return just the name of the method/field
("concat" "contains" "contentEquals")
> (.? "string instance" #"^con" :name) ;; works with instances also
("concat" "contains" "contentEquals")
> (.? "a string instance" :static :name :public :method) ; all public static methods
("copyValueOf" "format" "join" "valueOf")
> (.? "a string instance" #"^t" :instance :name :public :method) ;; all public instance methods that start with t
("toCharArray" "toLowerCase" "toString" "toUpperCase" "trim")

Related

Swap nested specific item in map finding by key value, the position in map

We have a cursor or atom map with this example data:
#<Cursor: [:customer] {:name Diego Peña,
:addresses [{:id 23, :province Madrid, :country 1, :descripcion aaeeeeeeee iii oooo4444, :locality Gali gali, :country_name SPAIN, :direccion Street Cierva, :id 3, :postalcode 30203, :principal true, :customer 17}
{:id 35, :province Madrid, :country nil, :descripcion yyy lalala3, :locality Lalala, :direccion calle Maria 3 , :postalcode 333, :principal false, :customer 17}
{:id 6, :province Madrid, :country 2, :descripcion otra direccioncita444, :locality Leleele, :country_name SPAIN, :direccion Direccion calle Ooo, :postalcode 1236, :main false, :customer 17}
{:id 27, :province Madrid, :country 1, :descripcion grandisima, :locality Alcantarilla, :country_name SPAIN, :direccion C/ 3 Mayo, :postalcode 3001, :main false, :customer 17}
]}>
I need to change the values of a searched address by id. I have managed to locate the address by the value of the id:
(defn get-address [pk]
(->> #db/customer :addresses (filter #(= (int pk) (int (:id %)))) first)
)
I can change all addresses with this: :ok #(swap! db/customer assoc-in [:addresses] %)}). I need to change data for a specific address from the API response.
I am close to getting it, but with this approach I am missing the position or the index of the item: #(swap! db/client assoc-in [:addresses ¿position or index in map?] %) we have the id of item address.
Perhaps this approach is wrong, a better one?
The assoc, assoc-in, update, and update-in functions work also on vectors. In Clojure, vectors are associative data structures where the key is the numeric index (O..n) and the value is the item at position n.
So you can do:
(assoc [:a :b :c] 1 :new-value)
;; ^ ^ ^
;; 0 1 2
;; => [:a :new-value :c]
Based on your example, you will need this:
(defn address-index-by-id
"Take an `address` map and look it up by `:id` in the `addresses` list.
Return the numeric index where it was found, nil if not found."
[address addresses]
(->> (map-indexed vector addresses)
;; produce a seq `([0 val-at-index-0] … [n val-at-index-n])`
(filter (fn [[_index {:keys [id]}]] (= id (:id address)))) ;; filter by id
(ffirst) ;; get the index of the first match
))
(defn set-address
"Take a `customer` map and an `address` map. Will put the `address` in the
customer's addresses list. If an address with the same :id key is already
present in this list, it will be overwritten."
[customer address]
(if-let [existing-index (address-index-by-id address (:addresses customer))]
(assoc-in customer [:addresses existing-index] address)
(update customer :addresses conj address)))
Usage:
(set-address {:name "Diego Peña"
:addresses []}
{:id 1
:province "Madrid"})
;; => {:name "Diego Peña", :addresses [{:id 1, :province "Madrid"}]}
(-> {:name "Diego Peña"
:addresses [{:id 1
:province "Madrid"
:main true}
{:id 2
:province "Barcelona"
:main false}]}
(set-address {:id 2
:province "Barcelona"
:main true})
(set-address {:id 1
:province "Madrid"
:main false}))
;; => {:name "Diego Peña", :addresses [{:id 1, :province "Madrid", :main false} {:id 2, :province "Barcelona", :main true}]}
;; And of course if your `customer` is stored in an Atom:
(swap! customer set-address {:id 1, :province "Madrid", :main true})
It looks like you are pulling data out of a database of some kind. If so, you should let the DB search for the ID in question. You can then read or update that record.
If you really need to do it in Clojure, you can search for the desired customer map using the tupelo.forest library. Here is an example with your data:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require [tupelo.forest :as tf]))
(def customer
{:name "Diego Peña",
:addresses
[{:id 23
:province "Madrid"
:country 1
:descripcion " aaeeeeeeee iii oooo4444"
:locality "Gali gali"
:country_name "SPAIN"
:direccion "Street Cierva"
:postalcode 30203
:principal true
}
{:id 35
:province "Madrid"
:country nil
:descripcion "yyy lalala3"
:locality "Lalala"
:direccion "calle Maria 3"
:postalcode 333
:principal false
:customer 17}
{:id 6
:province "Madrid"
:country 2
:descripcion "otra direccioncita444"
:locality "Leleele"
:country_name "SPAIN"
:direccion "Direccion calle Ooo"
:postalcode 1236
:main false
:customer 17}
{:id 27
:province "Madrid"
:country 1
:descripcion "grandisima"
:locality "Alcantarilla"
:country_name "SPAIN"
:direccion "C / 3 Mayo"
:postalcode 3001
:main false
:customer 17}
]})
and some code to find customer with :id 35
(dotest
(tf/with-forest (tf/new-forest)
(let [root-hid (tf/add-tree-edn customer)
cust-num 35
paths-found (tf/find-paths root-hid [:**
{:tag :tupelo.forest/entry, :tupelo.forest/key :id}
{:tupelo.forest/value cust-num}])
cust-path-rev (reverse (last paths-found))
cust-entity-hid (xthird cust-path-rev)
]
(is= (tf/hid->bush (xfirst cust-path-rev)) [#:tupelo.forest{:value 35, :index nil}])
(is= (tf/hid->tree cust-entity-hid)
{:tag :tupelo.forest/entity,
:tupelo.forest/index 1,
:tupelo.forest/kids [{:tag :tupelo.forest/entry,
:tupelo.forest/key :locality,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value "Lalala", :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :customer,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value 17, :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :descripcion,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value "yyy lalala3", :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :direccion,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value "calle Maria 3", :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :id,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value 35, :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :postalcode,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value 333, :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :principal,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value false, :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :province,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value "Madrid", :index nil}]}
{:tag :tupelo.forest/entry,
:tupelo.forest/key :country,
:tupelo.forest/kids [#:tupelo.forest{:kids [], :value nil, :index nil}]}]})
You can convert the data from the internal tree format back into EDN data:
(is= (tf/hid->edn cust-entity-hid)
{:locality "Lalala",
:customer 17,
:descripcion "yyy lalala3",
:direccion "calle Maria 3",
:id 35,
:postalcode 333,
:principal false,
:province "Madrid",
:country nil})
)))
You never really said how you want to change the data. Again, it would probably be best to do this with the DB rather than changing Clojure data structures.
Update
Another option is to use a recursive walk like clojure.walk/postwalk or the enhanced tupelo.core/walk-with-parents. Example to uppercase street name for cust ID #35
(dotest
(let [modified (t/walk-with-parents customer
{:enter (fn [parents item]
(with-nil-default item
(when (and (map? item)
(t/submap? {:id 35} item))
(spyx-pretty item)
(update item :direccion str/upper-case))))})]
(is= modified {:name "Diego Peña",
:addresses
[{:locality "Gali gali",
:descripcion " aaeeeeeeee iii oooo4444",
:country_name "SPAIN",
:direccion "Street Cierva",
:id 23,
:postalcode 30203,
:principal true,
:province "Madrid",
:country 1}
{:locality "Lalala",
:customer 17,
:descripcion "yyy lalala3",
:direccion "CALLE MARIA 3",
:id 35,
:postalcode 333,
:principal false,
:province "Madrid",
:country nil}
{:locality "Leleele",
:customer 17,
:descripcion "otra direccioncita444",
:country_name "SPAIN",
:direccion "Direccion calle Ooo",
:id 6,
:postalcode 1236,
:main false,
:province "Madrid",
:country 2}
{:locality "Alcantarilla",
:customer 17,
:descripcion "grandisima",
:country_name "SPAIN",
:direccion "C / 3 Mayo",
:id 27,
:postalcode 3001,
:main false,
:province "Madrid",
:country 1}]})))

Cleaner Way to Sort and Order a Vector of Maps in Clojure?

I have a vector of maps wherein I need to remove the maps where the value of the name key is a duplicate, keeping the one that has the highest value of age. I have a solution but I don't think it looks clean. Is there a better way to do it without breaking it up into multiple functions?
Here is my data:
(def my-maps
[{:name "jess", :age 32}
{:name "ruxpin", :age 4}
{:name "jess", :age 35}
{:name "aero", :age 33}
{:name "banner", :age 4}])
Here is my solution:
(map first (vals (group-by :name (reverse (sort-by :name my-maps)))))
Result:
({:name "ruxpin", :age 4} {:name "jess", :age 35} {:name "banner", :age 4} {:name "aero", :age 33})
another way is the combination of group-by and max-key. The advantage of this method is that you don't need to sort your collection, and sort in turn has an impact on performance and if it can be avoided it should be.
(for [[_ vs] (group-by :name my-maps)]
(apply max-key :age vs))
;;=> ({:name "jess", :age 35}
;; {:name "ruxpin", :age 4}
;; {:name "aero", :age 33}
;; {:name "banner", :age 4})
short version
(->> my-set
(sort-by (juxt :name :age) #(compare %2 %1)) ; sort-by :name, :age in reverse order
(partition-by :name)
(map first))
a transducer version
(def xf (comp (partition-by :name) (map first)))
(->> my-set
(sort-by (juxt :name :age) #(compare %2 %1))
(into [] xf))
for large dataset, the transducer should be better
Your original solution was actually broken unfortunately. It just seemed to work because of the order you had the data in my-set in. Note how you never actually sort by age, so you can never guarantee what order the ages are in.
I solved this with another call to map:
(->> my-set (group-by :name)
(vals)
; Sort by age each list that group-by returns
(map #(sort-by :age %))
(map last)) ; This could also happen in the above map
Note how I'm sorting each :name group by :age, then I take the last of each grouping.
I would do it a little differently, using the max function instead of sorting:
(def my-maps
[{:name "jess", :age 32}
{:name "ruxpin", :age 4}
{:name "jess", :age 35}
{:name "aero", :age 33}
{:name "banner", :age 4}])
(dotest
(let [grouped-data (group-by :name my-maps)
name-age-maps (for [[name map-list] grouped-data]
(let [max-age (apply max
(map :age map-list))
name-age-map {name max-age}]
name-age-map))
final-result (reduce into {} name-age-maps)]
final-result))
with results:
grouped-data =>
{"jess" [{:name "jess", :age 32} {:name "jess", :age 35}],
"ruxpin" [{:name "ruxpin", :age 4}],
"aero" [{:name "aero", :age 33}],
"banner" [{:name "banner", :age 4}]}
name-age-maps =>
({"jess" 35} {"ruxpin" 4} {"aero" 33} {"banner" 4})
final-result =>
{"jess" 35, "ruxpin" 4, "aero" 33, "banner" 4}
Compare by vector fields with different weight and data type (size has more weight), size is descending, name is ascending:
(def some-vector [{:name "head" :size 3}
{:name "mouth" :size 1}
{:name "nose" :size 1}
{:name "neck" :size 2}
{:name "chest" :size 10}
{:name "back" :size 10}
{:name "abdomen" :size 6}
])
(->> (some-vector)
(sort #(compare (str (format "%3d" (:size %2)) (:name %1))
(str (format "%3d" (:size %1)) (:name %2))
)))

Om Next Tutorial: Correctly calling the get-people function

I'm currently following along the om-next tutorial. In the Adding Reads section, there's a function get-people is defined. Along with this function, the init-data map is defined that contains a list of people.
(defn get-people [state key]
(let [st #state]
(into [] (map #(get-in st %)) (get st key))))
(def init-data {:list/one
[{:name "John", :points 0}
{:name "Mary", :points 0}
{:name "Bob", :points 0}],
:list/two
[{:name "Mary", :points 0, :age 27}
{:name "Gwen", :points 0}
{:name "Jeff", :points 0}]})
Here's my attempt to call this function.
(get-people (atom init-data) :list/one) ;; => [nil nil nil]
As you can see, I simply get back a vector of nils . I don't quite understand how I should call this function. Could somebody help me out? Thank you!
Alright, I figured it out.
init-data is not the correct data structure to call get-people with. The initial data must first be "reconciled" using Om's reconciler. You can find more information regarding the reconciler here in the tutorial's Normalization section.
Reconciling the init-data map and then derefing the data returns this normalized data structure:
{:list/one
[[:person/by-name "John"]
[:person/by-name "Mary"]
[:person/by-name "Bob"]],
:list/two
[[:person/by-name "Mary"]
[:person/by-name "Gwen"]
[:person/by-name "Jeff"]],
:person/by-name
{"John" {:name "John", :points 0},
"Mary" {:name "Mary", :points 0, :age 27},
"Bob" {:name "Bob", :points 0},
"Gwen" {:name "Gwen", :points 0},
"Jeff" {:name "Jeff", :points 0}}}
Here is a valid call to the get-people function using the reconciled init-data:
; reconciled initial data
(def reconciled-data
{:list/one
[[:person/by-name "John"]
[:person/by-name "Mary"]
[:person/by-name "Bob"]],
:list/two
[[:person/by-name "Mary"]
[:person/by-name "Gwen"]
[:person/by-name "Jeff"]],
:person/by-name
{"John" {:name "John", :points 0},
"Mary" {:name "Mary", :points 0, :age 27},
"Bob" {:name "Bob", :points 0},
"Gwen" {:name "Gwen", :points 0},
"Jeff" {:name "Jeff", :points 0}}}
; correct function call
(get-people (atom reconciled-data) :list/one)
; returned results
[{:name "John", :points 0}
{:name "Mary", :points 0, :age 27}
{:name "Bob", :points 0}]
Here's what's happening:
First, the function retrieves the value associated with the :list/one key. In this case, the value is a vector of paths into a map (each path is itself a vector).
Next, map over the paths and call the anonymous function on each vector. One of the calls would look like (get-in st [:person/by-name "John"]) and return {:name "John", :points 0}.
Return the results as a vector
If anybody is reading this and wants further clarification, please let me know.

how to extract data in nested list/vector clojure

I have parse xml and get the following result
(({:tag :Column,
:attrs {:Name "VENDOR_KEY", :Type "Int", :NotNull "Yes"},
:content nil}
{:tag :Column,
:attrs {:Name "RETAILER_KEY", :Type "Int", :NotNull "Yes"},
:content nil}
{:tag :Column,
:attrs {:Name "ITEM_KEY", :Type "Int", :NotNull "Yes"},
:content nil})
({:tag :Column,
:attrs {:Name "Store_Key", :Type "Int", :NotNull "Yes"},
:content nil}))
then how to convert it to the following, basically I want to extract the value of key :attrs in nested list.
(
({:Name "VENDOR_KEY", :Type "Int", :NotNull "Yes"},
{:Name "RETAILER_KEY", :Type "Int", :NotNull "Yes"},
{:Name "ITEM_KEY", :Type "Int", :NotNull "Yes"}),
({:Name "Store_Key", :Type "Int", :NotNull "Yes"})
)
so yes right here your solution as
hsestupin said
(map #(map :attrs %) result)
i am assuming result is your input data.

Vector expected in Clojure?

Currently I am getting this error.
Parameter declaration symmetrize-body-parts should be a vector,
compiling:(braveclojure/core.clj:41:49)
My core.clj file
(ns braveclojure.core
(:gen-class))
(def asym-hobbit-body-parts [{:name "head" :size 3}
{:name "left-eye" :size 1}
{:name "left-ear" :size 1}
{:name "mouth" :size 1}
{:name "nose" :size 1}
{:name "neck" :size 2}
{:name "left-shoulder" :size 3}
{:name "left-upper-arm" :size 3}
{:name "chest" :size 10}
{:name "back" :size 10}
{:name "left-forearm" :size 3}
{:name "abdomen" :size 6}
{:name "left-kidney" :size 1}
{:name "left-hand" :size 2}
{:name "left-knee" :size 2}
{:name "left-thigh" :size 4}
{:name "left-lower-leg" :size 3}
{:name "left-achilles" :size 1}
{:name "left-foot" :size 2}])
(defn needs-matching-part? [part]
(re-find #"^left-" (:name part)))
(defn make-matching-part [part] {:name (clojure.string/replace (:name part) #"^left-" "right-")
:size (:size part)})
(defn symmetrize-body-parts
"Expects to see a seq of maps which have a :name and :size"
[asym-body-parts]
(loop [remaining-asym-parts asym-body-parts
final-body-parts []]
(if (empty? remaining-asym-parts)
final-body-parts
(let [[part & remaining] remaining-asym-parts
final-body-parts (conj final-body-parts part)]
(if (needs-matching-part? part)
(recur remaining (conj final-body-parts (make-matching-part part)))
(recur remaining final-body-parts))))))
(defn -main (symmetrize-body-parts asym-hobbit-body-parts))
I use lein run in the clojure app folder but it is raising the above error. I have switched different things around in regards to the parameter brackets [] location for the symmetrize-body-parts function definition from above to below the docstring as well but to no avail. What is going on here?
Following the tutorial from here.
Try:
(defn -main []
(symmetrize-body-parts asym-hobbit-body-parts))