Take N non-empty items from clojure set - collections

I have a set (I think) of items; similar to this:
(def a ({:answers 3 :comments 12} {} {} {:answers 43 :comments 23} {}))
I want to ideally remove all empty items in that list, but keep the set intact otherwise.. what I am trying to do is:
(defn drop-empty-items
[a]
(take-when #(not empty? %) a))
but this obviously doesn't work at all..
How do I do this, please?
I'm trying to return something to the effect of:
({:answers 3 :comments 12} {:answers 43 :comments 23})
from drop-empty-items

(def a '({:answers 3 :comments 12} {} {} {:answers 43 :comments 23} {}))
(remove empty? a)
;=> ({:answers 3, :comments 12} {:answers 43, :comments 23})

Related

Which approach to find multiple totals more closely follows the functional programming paradigm?

Say you have an array of objects with the structure like {id: 1, type: 'A', value: 10} want to find the total of type A, type B, and type C.
It would be more efficient to initialize the total variables and then loop through the array once, adding the the total variables based on type, than to use a reduce function for each total, in effect looping over the array 3 times.
However, from what I understand from the functional programming paradigm, functions should not manipulate anything outside of it internal scope and functions should have just one purpose, so the latter approach would be preferred.
Approach 1: initialize a variable for each of the three types, loop once and add to each total based on type
Approach 2: use reduce function for each total type.
Which one is preferred?
You can use a single fold/reduce if you use a record containing the three values as the state e.g. in clojure:
(defn sum-inputs [inputs]
(reduce (fn [acc {:keys [type value]}]
(update acc (keyword type) + value))
{:A 0 :B 0 :C 0}
inputs))
then
(sum-inputs [{:id 1 :type "A" :value 10}
{:id 2 :type "B" :value 12}
{:id 3 :type "B" :value 7}
{:id 4 :type "C" :value 40}])
in Javascript it looks like you can use Array.reduce:
const input = [{id: 1, type: "A", value: 4}, {id: 2, type: "B", value: 3}, {id: 3, type: "B", value: 9}, {id: 4, type: "C", value: 2}]
input.reduce(function(acc, i) { acc[i.type] += i.value; return acc; }, {A: 0, B: 0, C: 0})
note this mutates the accumulator record in place.

Clojure - filter nested map on innermost level

what would be the best way of filtering the following nested map, keeping the nested map structure. In my example Alice and Bob can be duplicated, e.g. the same employee can be working in several different plants at a time.
(def universe
{:customer1
{:plant1
{ "Alice" {:age 35 :sex "F"}
"Bob" {:age 25 :sex "M"}}
:plant2 {}}
:customer2 {}
})
I would like to for example filter by age >30 and return the same map structure. Ideally this would work for any nested map depth, filtering on the innermost level. Expected result:
(def universe
{:customer1
{:plant1
{ "Alice" {:age 35 :sex "F"}
}
:plant2 {}}
:customer2 {}
})
I've looked at clojure filter nested map to return keys based on inner map values but it doesn't look to be solving my problem. Thank you,
It is very similar to one of previous questions:
(use '[com.rpl.specter])
(let [input {:customer1
{:plant1
{"Alice" {:age 35 :sex "F"}
"Bob" {:age 25 :sex "M"}}
:plant2 {}}
:customer2 {}}
desired-output {:customer1
{:plant1 {"Alice" {:age 35 :sex "F"}}
:plant2 {}}
:customer2 {}}
RECUR-MAP (recursive-path [] p (cond-path map? (continue-then-stay [MAP-VALS p])))]
(clojure.test/is (= (setval [RECUR-MAP (pred :age) #(> 30 (:age %))] NONE input)
desired-output)))
Your data is a bit unusual in that one would normally expect :customer1, :customer2 etc to be different entries in a vector. For semi-structured data like this, I would consider postwalk:
(ns tst.demo.core
(:use tupelo.core demo.core tupelo.test)
(:require
[clojure.walk :as walk] ))
(def universe
{:customer1
{:plant1
{"Alice" {:age 35 :sex "F"}
"Bob" {:age 25 :sex "M"}}
:plant2 {}}
:customer2 {}})
(def age-of-wisdom 30)
(defn wisdom-only
[form]
(let [filter-entry? (when (map-entry? form)
(let [[-name- details] form
age (:age details)] ; => nil if missing
(and age ; ensure not nil
(< age age-of-wisdom))))]
(if filter-entry?
{}
form)))
(walk/postwalk wisdom-only universe) =>
{:customer1
{:plant1
{"Alice" {:age 35, :sex "F"}}
:plant2 {}}
:customer2 {}}
Thanks to #akond for the answer, reading the code made me think of a non specter solution. Still, slightly surprised there's no easy way to apply filter in this use case.
(defn recursive-filter [pred k m]
(letfn [(pair-filter [pair] (if (pred (k (second pair))) pair nil))]
(into {}
(for [a m]
(if (empty? (second a))
[(first a) {}]
(if (contains? (second a) k)
(pair-filter a)
[(first a) (recursive-filter pred k (second a))]))))))

How to prevent close!-ing before put-ing in onto-chan

I'd like to run a code like
(->> input
(partition-all 5)
(map a-side-effect)
dorun)
asynchronously dividing input and output(a-side-effect).
Then I've written the code to experiment below.
;; using boot-clj
(set-env! :dependencies '[[org.clojure/core.async "0.2.374"]])
(require '[clojure.core.async :as async :refer [<! <!! >! >!!]])
(let [input (range 18)
c (async/chan 1 (comp (partition-all 5)
(map prn)))]
(async/onto-chan c input false)
(async/close! c))
explanation for this code:
Actually elements in input and its quantity is not defined before running and elements in input is able to be taken by some numbers from 0 to 10.
async/onto-chan is used to put a Seq of elements (a fragment of input) into the channel c and will be called many times thus the 3rd argument is false.
prn is a substitute for a-side-effect.
I expected the code above prints
[0 1 2 3 4]
[5 6 7 8 9]
[10 11 12 13 14]
[15 16 17]
in REPL however it prints no characters.
And then I add a time to wait, like this
(let [c (async/chan 1 (comp (partition-all 5)
(map prn)))]
(async/onto-chan c (range 18) false)
(Thread/sleep 1000) ;wait
(async/close! c))
This code gave my expected output above.
And then I inspect core.async/onto-chan.
And I think what happend:
the channel c was core.async/close!ed in my code.
each item of the argument of core.async/onto-chan was put(core.async/>!) in vain in the go-loop in onto-chan because the channel c was closed.
Are there sure ways to put items before close!ing?
write a synchronous version of onto-chan not using go-loop?
Or is my idea wrong?
Your second example with Thread.sleep only ‘works’ by mistake.
The reason it works is that every transformed result value that comes out of c’s transducer is nil, and since nils are not allowed in channels, an exception is thrown, and no value is put into c: this is what allows the producer onto-chan to continue putting into the channel and not block waiting. If you paste your second example into the REPL you’ll see four stack traces – one for each partition.
The nils are of course due to mapping over prn, which is a side-effecting function that returns nil for all inputs.
If I understand your design correctly, your goal is to do something like this:
(defn go-run! [ch proc]
(async/go-loop []
(when-let [value (<! ch)]
(proc value)
(recur))))
(let [input (range 18)
c (async/chan 1 (partition-all 5))]
(async/onto-chan c input)
(<!! (go-run! c prn)))
You really do need a producer and a consumer, else your program will block. I’ve introduced a go-loop consumer.
Very generally speaking, map and side-effects don’t go together well, so I’ve extracted the side-effecting prn into the consumer.
onto-chan cannot be called ‘many times’ (at least in the code shown) so it doesn’t need the false argument.
taking megakorre's idea:
(let [c (async/chan 1 (comp (partition-all 5)
(map prn)))
put-ch (async/onto-chan c (range 18) false)]
(async/alts!! [put-ch])
(async/close! c))

Clojure: search/replace values in a dynamic nested map/seq

I have a dynamically created map data structure which will later on be parsed into JSON. Therefore the nesting levels, etc. are unknown and depend on the data.
If a key has multiple values, they are represented as maps inside a sequence.
Here is an example:
{:key "value"
:anotherKey "anotherValue"
:foo "test"
:others [ {:foo "test2"} {:foo "test3"} ]
:deeper {:nesting {:foo "test4"} }
}
I now want to search for the key :foo and append "/bar" to the value.
The result should return the modified map:
{:key "value"
:anotherKey "anotherValue"
:foo "test/bar"
:others [ {:foo "test2/bar"} {:foo "test3/bar"} ]
:deeper {:nesting {:foo "test4/bar"} }
}
What would be a clean and simple way to achieve that?
I tried a recursive approach but beside the memory problem of large data structures I'm struggling with returning my appended values.
There might be something simpler than this:
(clojure.walk/prewalk
(fn [m]
(if (and (map? m) (:foo m))
(update-in m [:foo] #(str % "/bar"))
m))
{:key "value"
:anotherKey "anotherValue"
:foo "test"
:others [{:foo "test2"} {:foo "test3"}]
:deeper {:nesting {:foo "test4"}}})
=>
{:anotherKey "anotherValue",
:key "value",
:deeper {:nesting {:foo "test4/bar"}},
:foo "test/bar",
:others [{:foo "test2/bar"} {:foo "test3/bar"}]}

Looking up values in a map with a vector of integer keys in Clojure

I have a map like this:
(def my-map {43423 43.3, 63452 32.02, 823828 67.43, ...})
and a vector of keys that are in a different order:
(def my-keys [63452 823828 43423 ...])
How can I call the my-keys vector on my-map to pull out the values and maintain the order of the vector, as below?
;=> [32.02 67.43 43.3 ...]
Any datatype returned is fine as long as the order is maintained.
Use map
(map my-map my-keys)
;=> (32.02 67.43 43.3)
This works because {} maps implement the function interface by looking up the argument in themselves.
({:foo 1 :bar 2} :bar)
;=> 2

Resources