Good Morning!
Good morning
Morn'
Morning π
morning
morning
Morning
mΓ₯ningΒ‘
What's a good name for this function?
(defn f [m]
(reduce (fn [A [key val]] (update A val conj key)) {} m))
It's inverting a map, but the new values are a collection of the keys that have a given old value.
I had map-invert-with-collect
or collect-values
map-invert
would sound good to me
have you checked out https://clojure.github.io/clojure/clojure.set-api.html#clojure.set/map-invert though?
oh that doesn't tolarate multi mappings from v->k though
maybe multimap-invert
? just to labour the point
Yeah, map-invert
is a name collision unfortunately π I like multimap invert, though maybe that implies it inverts a multimap, rather than returns one? Maybe map-invert-to-multi
that sounds just fine fthat sounds just
I find it a bit annoying that there isn't a Clojure function that lets you do things like that (as far as I know?) that doesn't involve you stopping to think about what on earth's going on
Like, the Kotlin equivalent is something like map.entries.groupBy({ it.value }) { it.key }
which I find easy to scan for it being probably correct
Isn't a map with unknown keys kinda useless?
Oh wait, no, you're basically just doing (group-by val {:a 10 :b 20 :c 10})
, not what I was thinking π
@dominicm conceptually yeah, but the output I want is a bit different
(map-invert-multi {:a 10 :b 20 :c 10})
;; => {10 (:c :a), 20 (:b)}
(group-by val {:a 10 :b 20 :c 10})
;; => {10 [[:a 10] [:c 10]], 20 [[:b 20]]}
@allaboutthatmace1789 how are you consuming this downstream?
In this context, it's part of a quick game of life implementation
(def blinker [[0 0] [0 1] [0 2]])
(defn neighbours [[x y]]
(for [xvar [-1 0 1]
yvar [-1 0 1]
:when (not= xvar yvar 0)]
[(+ x xvar) (+ y yvar)]))
(defn map-invert-multi [m]
(reduce (fn [n [key val]] (update n val conj key)) {} m))
(defn new-active-cells [already-active-cells]
(let [cells-with-n-active-neigbours
(->> already-active-cells
(mapcat neighbours)
frequencies
map-invert-multi)]
(sort (concat (get cells-with-n-active-neigbours 3)
(filter (set already-active-cells) (get cells-with-n-active-neigbours 2))))))
(-> blinker
new-active-cells
new-active-cells)
so after map-invert-multi-ing, I want to concat everything with key 3 and a filtered list of things with key 2.So really, you just want to track how many things have 2/3 neighbours.
Yes, with the caveat that I need to distinguish between the 2 and 3 neighbour cases
Yeah, for sure.
What if they have 4 active neighbours? (I've never actually done game of life!)
If an active cell has > 3 neighbours it's 'overcrowded' and dies - here's a complete mapping:
C N new C
1 0,1 -> 0 # Lonely
1 4,5,6,7,8 -> 0 # Overcrowded
1 2,3 -> 1 # Lives
0 3 -> 1 # It takes three to give birth!
0 0,1,2,4,5,6,7,8 -> 0 # Barren
But stated another way, any cell with 3 neighbours is alive the next round, any with 2 neighbours is alive in the next round if it's alive nowEverything else is dead
I guess an interesting way to flip this would be to use frequencies directly?
(reduce-kv (fn [state cnt neighbours] (case cnt (0 1) (lonely β¦) 3 (give-birth β¦))) state (frequencies β¦))
I was trying to write the program to be as close as possible to the description of the rules of the game, hence the
new-active-cells = (concat (get cells-with-n-active-neigbours 3)
(filter (set already-active-cells) (get cells-with-n-active-neigbours 2)))
> I guess an interesting way to flip this would be to use frequencies directly?
I think so, but you'd have to have a 5 branch conditional, like (c = 1, N = 0|1) (lonely ,,,)
- unless I'm misunderstanding what the lonely
, give-birth
fns are doing?
Oh, I didn't pay enough attention π