Fork me on GitHub
#beginners
<
2017-03-22
>
byron-woodfork17:03:50

Question...Hopefully this explains is thoroughly...I know the answer to this is right in front of me but I can't for the life of me think of what it is.

(def events [{:action "play" :value 3}
             {:action "stop" :value 4}]
             {:action "rewind" :value 1}])

(def original-map {:value 500})

(defn do-thing [original-map events]
  ; when event is 'play', add :value from event to the value in original-map
  ; when event is 'stop', add :value from event to the value in the original-map
  ; when event is 'rewind', subtract :value from event to the value in the original-map


  ; expected result {:value 506}
  )

So, I want (do-thing) to go through the collection of events and check to see what their action is. Once it see's play, it adds its value to original-map's value. It should then move onto the next event. In the event that :action is stop, it should add it's value to original-map's value. The expected result should be {:value 507}. I know I could just take the values from both events, add them up and add them to the original-map value. But that's not an option. I'm trying to go through the events and perform actions with them accordingly.

xsyn17:03:25

@byron-woodfork For a start you’re defining do-thing as a vector with two elements, I assume you want it to be a function?

byron-woodfork17:03:00

whoops, yeah. I'll edit.

xsyn18:03:15

The purpose of this confuses me

xsyn18:03:27

If an action is anything, add the value to the map?

drayah18:03:32

yea.. could you give a larger events example

xsyn18:03:27

Are there going to be different events? Different actions? etc

byron-woodfork18:03:35

@xsyn @drayah Yup. There would be multiple actions and events. I can extend the example code to reflect that. I started to but was trying to keep things as simple as possible.

xsyn18:03:51

@byron-woodfork Why I’m struggling is that I’m expecting to see a conditional of sorts, but I don’t really understand what that conditional looks like, because in both examples you’ve provided it’s the same thing

byron-woodfork18:03:06

@xsyn Yup. I see why that's confusing. I added an extra option. rewind. So when the action is rewind, it should instead subtract the value and not add.

byron-woodfork18:03:23

Does that clear things up at all?

sbauer18:03:39

this is some pretty ugly code and needs to be cleaned up, but how about?

(defn do-thing 
  [o-map evts]  
  (reduce (fn [acc e]
            (cond 
              (= (:action e) "play") {:value (+ (:value acc) (:value e))} ; when play
              (= (:action e) "stop") {:value (+ (:value acc) (:value e))} ; when stop
              :else {:value (:value acc)}; when anything else
              )) o-map evts))

byron-woodfork18:03:49

Hmmmmm. I'll have to experiment with that. It looks like the direction I was headed though.

xsyn18:03:33

Oh, that’s interesting, I thought it need to recur on itself until something changed, or it ran out of events

xsyn18:03:03

This is why scoping is important 😉

byron-woodfork18:03:53

@xsyn that's another route I was considering as well. I think it could be solved either way honestly.

byron-woodfork18:03:08

The recur option seemed right. But I kept confusing myself when thinking about removing events from the collection so the same events wouldn't be hit twice.

curlyfry18:03:00

@byron-woodfork My version:

(defn do-thing [original-map events]
  (reduce (fn [acc-map {:keys [action value]}]
            (if (#{"play" "stop"} action) (update acc-map :value + value) acc-map))
          original-map
          events))

sbauer19:03:38

(#{"play" "stop"} action) is a nice touch

byron-woodfork19:03:43

Agreed, I don't think I've ever seen that syntax though. Is there a name for it?

noisesmith19:03:56

it’s a hash-set literal, hash-sets when called as functions call get

noisesmith19:03:45

as do hash-maps, vectors, keywords, and symbols

camdenclark20:03:14

interesting, so hash-set literals return the value if it’s in the set, but vectors called as a function return the value at that index?

noisesmith20:03:38

camdenclark right - because hash-set can be thought of as a mapping from item to itself

noisesmith20:03:54

(and is often implemented that way, I forget if clojure does that though)

noisesmith20:03:40

or, another way to put it, hash-set implements get as “the value, if present in this set” and all associative clojure data types implement call as get

camdenclark20:03:22

I see. ((into #{} '(1 2 3)) 2) doesn’t work on /src, what’s up with that?

camdenclark20:03:34

It works in my repl

noisesmith20:03:22

why use (into #{} ‘(1 2 3)) instead of #{1 2 3} ? (or (into #{} [1 2 3]) at least)

camdenclark20:03:01

I was just curious if it would work, I’m just playing around with the syntax (very new to functional programming and clojure)

noisesmith20:03:16

oh, right, so all hash-sets work that way, whether or not defined as literals

camdenclark20:03:29

is that the preferred way in clojure to assert that a value is inside a vector? Turn it into a hash-set and get?

noisesmith20:03:47

for a vector, it only looks up by index

noisesmith20:03:02

there’s index-of to see if it is present

noisesmith20:03:55

err. .indexOf - I wonder why I thought index-of worked

seancorfield23:03:38

@noisesmith clojure.string/index-of exists (as of 1.8).

seancorfield23:03:56

(but not for non-strings)

noisesmith23:03:08

@seancorfield ahh, that's clearly the one I was thinking of, thanks