Fork me on GitHub
#beginners
<
2016-02-08
>
agile_geek08:02:48

Anything can be a key in a map but typically you use keywords as they resolve to their own identity everytime and they are useful as they implement IFn to look themselves up in a map.

raphaelsaunier14:02:58

Hi, I'm looking for a function that is equivalent to PHP's compact() or ES6's “object literal property value shorthand”, which take a list of variables/symbols that exist in the current scope and return a map with the names and values of each one.

raphaelsaunier14:02:01

Here's what I came up with:

(defmacro compact
  [& args]
  (let [keys (map keyword args)
        vals `(~@args)]
    (zipmap keys vals) ))


; Example
(let [artist "The Beatles"
      track "Let It Be"]
  (compact artist track))
; => {:artist "The Beatles", :track "Let It Be"}

raphaelsaunier14:02:32

Surely there has to be a built-in function or a more idiomatic way to do this with Clojure?

akiva15:02:48

You don’t need the macro. You can just do (zipmap (map keyword [keyword-vec]) [vals-vec]).

akiva15:02:49

Or you can use reduce-kv.

Chris O’Donnell15:02:12

@raphaelsaunier: That looks like a reasonable solution to me, though you could avoid using a macro by passing in symbols and using eval. For the record, here's my version of your macro: (defmacro compact [& args] (into {} (map (juxt keyword identity) args))).

akiva15:02:25

Ah, juxt. Another one I always forget about.

raphaelsaunier15:02:31

@akiva, right, but is there a way to generate keyword-vec programatically? I only ended up using a macro because with functions I could only get the values of the symbols but not their names…

Chris O’Donnell15:02:08

I think it would be better to implement it as a function as a function, like (defn compact [& args] (into {} (map (juxt keyword eval) args))). Then you'd call it like (let [a 1 b 2] (compact 'a 'b)).

raphaelsaunier15:02:00

@codonnell: nice! Hadn't thought of that! simple_smile

Chris O’Donnell15:02:36

As a function it's clearer you're working with the symbols, rather than their values.

bronsa15:02:23

using eval like that is rarely a good idea

raphaelsaunier15:02:43

Having said that, is there a more idiomatic way of solving this? I'm using this in a function that defines a couple of bindings and does a few computations within let and then returns a map.

bronsa15:02:00

@raphaelsaunier: in clojure we rarely use those kind of "magic" macros that rely on locals names

akiva15:02:05

@raphaelsaunier, I think @codonnell is on the right track here.

akiva15:02:51

I wouldn’t try to use the binding symbols themselves but have that information as part of the val.

Chris O’Donnell15:02:17

@raphaelsaunier: It's hard to say without more context. If there are too many variables to explicitly write the map, you should probably have them already grouped in a data structure which tells you what's what.

raphaelsaunier15:02:02

Thanks! Yeah sorry, I realised that my last question was a bit too vague after hitting enter. I'm not returning that many variables (<5), but it's just a convenience function that you get used to very quickly when writing ES6.

Chris O’Donnell16:02:34

That's how I would write your function, I think.

Chris O’Donnell16:02:45

But maybe with slightly more correct parens.

raphaelsaunier16:02:12

Thanks! Yes obviously, but I get the gist!

olegakbarov21:02:03

Guys, totally a newbie question How can i edit a date object? (i want to add to hours)

shaun-mahood21:02:05

@olegakbarov: Take a look at https://github.com/clj-time/clj-time it works really well for that

olegakbarov21:02:02

alright — i just needed to parse the string 😅 (t/plus (f/parse iso-8601 2016-02-06T12:45:00) (t/hours 2))