clojure-uk

A place for people in the UK, near the UK, visiting the UK, planning to visit the UK or just vaguely interested to randomly chat about things (often vi and emacs, occasionally clojure). More general the #ldnclj
dharrigan 2020-12-18T06:20:07.220900Z

Good Morning!

jiriknesl 2020-12-18T06:51:42.221100Z

Good morning

2020-12-18T07:20:51.221300Z

Morn'

yogidevbear 2020-12-18T08:27:52.221600Z

Morning πŸ™‚

thomas 2020-12-18T08:41:19.221800Z

morning

alexlynham 2020-12-18T08:53:07.221900Z

morning

2020-12-18T09:02:58.222300Z

Morning

mccraigmccraig 2020-12-18T10:10:25.222500Z

mΓ₯ningΒ‘

Joe 2020-12-18T13:02:57.224500Z

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

2020-12-18T13:05:49.224900Z

map-invert would sound good to me

2020-12-18T13:07:12.225200Z

have you checked out https://clojure.github.io/clojure/clojure.set-api.html#clojure.set/map-invert though?

2020-12-18T13:08:04.225800Z

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

2020-12-18T13:08:40.226200Z

maybe multimap-invert ? just to labour the point

Joe 2020-12-18T13:13:52.228300Z

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

2020-12-18T13:20:39.228800Z

that sounds just fine fthat sounds just

Conor 2020-12-18T13:31:16.228900Z

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

Conor 2020-12-18T13:32:16.229Z

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

dominicm 2020-12-18T13:37:16.229200Z

Isn't a map with unknown keys kinda useless?

dominicm 2020-12-18T13:38:15.229300Z

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

Joe 2020-12-18T13:51:15.230600Z

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

dominicm 2020-12-18T14:23:08.231400Z

@allaboutthatmace1789 how are you consuming this downstream?

Joe 2020-12-18T14:26:50.234100Z

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.

dominicm 2020-12-18T14:31:35.234200Z

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

Joe 2020-12-18T14:33:09.234800Z

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

dominicm 2020-12-18T14:33:26.234900Z

Yeah, for sure.

dominicm 2020-12-18T14:33:37.235Z

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

Joe 2020-12-18T14:36:35.237300Z

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

Joe 2020-12-18T14:36:44.237500Z

Everything else is dead

dominicm 2020-12-18T14:40:42.238600Z

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

Joe 2020-12-18T14:40:50.238700Z

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

Joe 2020-12-18T14:54:41.241400Z

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

dominicm 2020-12-18T17:25:40.241500Z

Oh, I didn't pay enough attention 😁