Fork me on GitHub
#clojure-uk
<
2020-12-18
>
dharrigan06:12:07

Good Morning!

jiriknesl06:12:42

Good morning

Joe13:12:57

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

Ben Hammond13:12:49

map-invert would sound good to me

Ben Hammond13:12:04

oh that doesn't tolarate multi mappings from v->k though

Ben Hammond13:12:40

maybe multimap-invert ? just to labour the point

Joe13:12:52

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

Ben Hammond13:12:39

that sounds just fine fthat sounds just

Conor13:12:16

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

Conor13:12:16

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

dominicm13:12:16

Isn't a map with unknown keys kinda useless?

dominicm13:12:15

Oh wait, no, you're basically just doing (group-by val {:a 10 :b 20 :c 10}), not what I was thinking 😁

Joe13:12:15

@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]]}

dominicm14:12:08

@allaboutthatmace1789 how are you consuming this downstream?

Joe14:12:50

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.

dominicm14:12:35

So really, you just want to track how many things have 2/3 neighbours.

Joe14:12:09

Yes, with the caveat that I need to distinguish between the 2 and 3 neighbour cases

dominicm14:12:26

Yeah, for sure.

dominicm14:12:37

What if they have 4 active neighbours? (I've never actually done game of life!)

Joe14:12:35

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 now

Joe14:12:44

Everything else is dead

dominicm14:12:42

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 …))

Joe14:12:50

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)))

Joe14:12:41

> 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?

dominicm17:12:40

Oh, I didn't pay enough attention 😁