Hello, is there a better way to extract an item from a collection based on its attribute than
(some
#(when
(= (:producer %) "Ferrari")
%)
cars)
? (Since some
returns the result of the test and not the item, I have to wrap the pred in a when
to return the item instead of true
.) Thanks!@holyjak (first (filter #(= "Ferrari" (:producer %)) cars))
would work if you don't mind the search going further than the first match (chunking).
@seancorfield Thanks for the answer. I have a beginner question. I use the filter first pattern all the time. Sometimes I think if there a function in clojure that does something like “filter-and-return-first-element” ?
Is it good idea to make utility function that does something like that and use it or should I always write (first (filter ...)
every time?
@avichalp I would just use (first (filter ...))
. The only times it might matter are: if you filtering predicate is extremely expensive to run or either the predicate or the sequence being realized have side effects. In those situations you might want more control of the sequence and the filtering operation (and you'd certainly be out of "beginner" territory at that point).
Make sense. Thanks for answering.
If the collection is not enormous I often find myself transforming it into a map and then doing a lookup. My favourite function atm is:
(defn index-by
([idx-fn coll]
(index-by idx-fn identity coll))
([idx-fn value-fn coll]
(into {} (map (juxt idx-fn value-fn)) coll)))
Which can be used in flexible ways.. For example in this case.
(def cars [{:producer "Ferrari"}
{:producer "Porsche"}
{:producer "Mazda"}])
(index-by :producer cars)
=> {"Ferrari" {:producer "Ferrari"},
"Porsche" {:producer "Porsche"},
"Mazda" {:producer "Mazda"}}
And of course there’s group-by
in core which works if there are many Ferraris etc..
☝️:skin-tone-2: Yes, this is a good approach. We have a similar function to index-by
at work.
Thanks! I had no idea it so so smart as not to continue to filter the rest of the sequence after the current chunk. Neat!
thank you all!
clojure.set/index
@hiredman That would return a map where the keys were like {:producer "Ferrari"}
right?
it returns something a little more complicated and more general
the values are sets of things with the same indexed values, and the keys are maps where the keys are the keys you index on
{{:producer "Ferrari"} #{{:producer "Ferrari" :some-other-key 1} {:producer "Ferrari" :another-key 5}}}
https://gist.github.com/hiredman/7d17d8d2b58c41ce95bf2db305b0f427