This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-25
Channels
- # bangalore-clj (2)
- # beginners (50)
- # boot (21)
- # cljs-dev (2)
- # cljsrn (1)
- # clojure (93)
- # clojure-russia (5)
- # clojure-spec (22)
- # clojure-uk (3)
- # clojurescript (24)
- # data-science (4)
- # datomic (1)
- # events (2)
- # fulcro (46)
- # graphql (9)
- # hoplon (16)
- # lumo (42)
- # off-topic (3)
- # perun (2)
- # protorepl (1)
- # re-frame (10)
- # reagent (12)
- # ring (1)
- # ring-swagger (1)
- # shadow-cljs (12)
- # specter (16)
- # unrepl (10)
Hello, a very beginner question here. Say I have a data structure like this and I want to select all the foods that have 3 pieces of cheese in them:
(def kitchen {:foods [{:type :sandwich :ingredients [{:type :bread :quantity 3}
{:type :cheese :quantity 2}
{:type :meatball :quantity 5}]}
{:type :sandwich :ingredients [{:type :bread :quantity 2}
{:type :cheese :quantity 3}
{:type :ham :quantity 2}]}
{:type :quiche :ingredients [{:type :egg :quantity 5}
{:type :cheese :quantity 5}]}]})
That is, I expect to return the ham sandwich and the quiche.
I understand how I could use Specter to navigate to all the quantities of cheese that are greater than 3:
(select [:foods ALL :ingredients ALL #(= (:type %) :cheese) :quantity #(>= % 3)] kitchen)
but what I really want to do is this:
(defn three-cheese-food? [food]
(->> food
(:ingredients)
(some
(fn [ingredient]
(and
(= (:type ingredient) :cheese)
(>= (:quantity ingredient) 3))))))
(filter three-cheese-food? (:foods kitchen))
Can I use Specter to do the work done in my filtering and three-cheese-food?
function? Thanks!@benstox yes, use selected?
(select [:foods
ALL
(selected? :ingredients ALL #(= :cheese (:type %)) :quantity (pred>= 3))]
kitchen)
Is there a Specter-y way to add multiple conditions to the filtering? I thought of this:
(select [:foods
ALL
(selected? :ingredients ALL #(= :cheese (:type %)) (multi-path [:quantity (pred>= 3)]
[:quality (pred>= 10)]))])
But this seems to act like an OR when what I want is an AND.cljs.user=> (require '[com.rpl.specter :as s :refer-macros [select transform]])
Could not require com.rpl.specter.navs in file com/rpl/specter.cljc
Could not require com.rpl.specter in file com/rpl/specter/navs.cljc
(new)
Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (NO_SOURCE_FILE <embedded>:1928:72)
Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (NO_SOURCE_FILE <embedded>:2539:92)
Function.cljs.js.require.cljs$core$IFn$_invoke$arity$5 (NO_SOURCE_FILE <embedded>:5849:145)
Object.cljs.js.load_macros (NO_SOURCE_FILE <embedded>:5883:41)
(NO_SOURCE_FILE <embedded>:5883:374)
Function.cljs.js.require.cljs$core$IFn$_invoke$arity$5 (NO_SOURCE_FILE <embedded>:5838:1)
Object.cljs.js.load_macros (NO_SOURCE_FILE <embedded>:5883:41)
(NO_SOURCE_FILE <embedded>:5905:316)
(NO_SOURCE_FILE <embedded>:5918:218)
Invalid regular expression: /\.js$/: Stack overflow
String.replace (NO_SOURCE_FILE <anonymous>)
Object.clojure.string.replace_all (NO_SOURCE_FILE <embedded>:1959:385)
Object.clojure.string.replace (NO_SOURCE_FILE <embedded>:1962:191)
(Object.cljs$stacktrace$remove_ext)
(Object.cljs$stacktrace$mapped_line_column_call)
(Object.cljs$stacktrace$mapped_frame)
Function.<anonymous> (evalmachine.<anonymous>:512:24)
Function.cljs.core.apply_to_simple.cljs$core$IFn$_invoke$arity$3 (NO_SOURCE_FILE <embedded>:771:157)
Function.cljs.core.apply_to_simple.cljs$core$IFn$_invoke$arity$2 (NO_SOURCE_FILE <embedded>:770:188)
Function.cljs.core.apply.cljs$core$IFn$_invoke$arity$2 (NO_SOURCE_FILE <embedded>:783:244)
@benstox selected?
is true if it navigates to at least one value, so multi-path
in a selected?
acts like an or
for multiple conditions just use multiple selected?
or multiple predicates in the path, e.g. [#(...) #(...) (selected? ...)]
@swizzard don't know anything about lumo, you'll probably have better luck in #clojurescript
@benstox I wrote a small lib to tackle such a selection more declarative: https://github.com/IamDrowsy/ebenbild
in your case (like {:type :cheese :quantity #(>= % 3) :quality #(>= % 10)})
would work
@nathanmarz Okay, makes sense. Thanks! @drowsy Interesting! I’ll try your library out.