Fork me on GitHub
#beginners
<
2017-07-11
>
bschrag04:07:27

Any orthodox way to create a map whose keyed values are vectors, adding elements to the vectors as you find objects containing their keys? Something like building page lists for entries in a book's index, finding topic mentions as you read from front to back. In Common Lisp, I'd just do (push item (gethash key table)). I gather this isn't allowed in Clojure, because it would mean bashing the map (as a whole — not the individual vectors). So, what does a Clojure programmer do?

onionpancakes04:07:18

like if you start with map {:foo [1 2 3]}, you want to push 4 to the vector value? so it becomes {:foo [1 2 3 4]} ?

onionpancakes04:07:56

you can use the update function to update map values.

onionpancakes04:07:34

so something like this (update m :foo conj 4) if we use m from my example.

onionpancakes04:07:36

but you have to make sure the key and values exists before you update.

onionpancakes04:07:54

otherwise it tries to conj a 4 onto a nil.

onionpancakes04:07:08

if the key-value doesn't exist in the map

bschrag05:07:07

Sounds good. Thanks!

seancorfield05:07:36

@scallions look at fnil to get around that /cc @bschrag

onionpancakes05:07:18

oh, that's something I haven't considered. very elegant

seancorfield05:07:40

(update m :foo (fnil conj []) 4) -- that will handle (:foo m) being nil

seancorfield05:07:18

(update {} :foo (fnil conj []) 4) => {:foo [4]}

moogey17:07:48

in this case, is there a difference between update and update-in?

seancorfield17:07:38

update is new-ish (Clojure 1.7?) and works for a single key. Prior to that being added, you had to do (update-in m [:my-key] f args) -- now you can do (update m :my-key f args)

seancorfield17:07:11

So, update-in for nested keys, update for a top-level key. Like assoc-in and assoc.

seancorfield17:07:39

(and, yeah, added in Clojure 1.7... just checked via (clojure.repl/source update))

moogey17:07:34

cool, thank you

seancorfield17:07:53

How's your Clojure learning going so far?

moogey17:07:08

its going well. I did a thing last saturday that scrapes(ish) expedia

lilactown15:07:26

how do I spit into a new resource file?

lilactown16:07:36

👍 as I'm reading more about the resources folder, i'm understanding that it's meant as a place for compile-time resources

rauh16:07:24

@lilactown They aren't even real files when you bundle up your application in a jar. They're URLs. You shouldn't call io/file on a resources either. Works during dev time but not at runtime

rauh16:07:06

Run this in a REPL: (io/resource "clojure/core.clj")

noisesmith16:07:11

@bschrag also if all the input is available at one time you can use group-by

Lone Ranger17:07:00

okay... as a dev coming from Python to Clojure (❤️ ) I feel really handicapped by my lack of understanding of Java for a lot of basic operational tasks. Things like unzipping files, etc, are all pretty foreign to me and a lot of that work gets farmed out to Java interop. Anytime I do an operation and a Java object is returned (i.e., file object), it's not obvious to me what the API for that object is. Is this one of those things you just have to look up one at a time, is there a fundamental set of Java knowledge one needs, or is there (hopefully) a systematic way of approaching situations where Java interop is required?

moogey17:07:35

Giving you a woot! Also coming from python, and trying to avoid java things, heh

Lone Ranger17:07:52

hahahaha :spock-hand: 😎 :spock-hand:

noisesmith18:07:19

the straightforward thing that works for me 95% of the time is to call class on the object, then use google to find the javadoc for that class

didibus04:07:12

Java isn't too complicated of a language, you shouldn't fear it. I think Clojure is more powerful when seen as an extension to Java.

didibus04:07:16

Having said that, have a look at https://github.com/Raynes/fs

manutter5117:07:42

I think if you have the basic Java constructs and conventions down, it’s not too hard to follow the online Java class docs. Maybe something like this would help? http://knuth.luther.edu/~bmiller/Java4Python/index.html

ghadi17:07:45

@goomba One super simple method is to call (javadoc TheClassName) in the REPL

ghadi17:07:16

(you may need to (require '[clojure.java.javadoc :refer (javadoc)]) depending on your REPL/context)

Lone Ranger17:07:25

beautiful, thanks @manutter51 @ghadi, great places to get started

fedreg19:07:13

Is there a concise way of destructuring two digit ints into individual numbers without converting them to chars first? thx!

ghadi19:07:57

why the constraint @fedreg ?

dpsutton19:07:21

concise usually means inline in a let binding and then it gets really cryptic. I'll bet you can spare a stackframe and make the name of the function descriptive

fedreg19:07:11

@ghadi No reason really, just keep having situations where I have to convert a number to str, destructure and then do js/parseInt on it. Seems like I’m missing something. Pretty new to Clojure so thought I’d check. Is that what most people do?

dpsutton19:07:34

(defn int->digits
  [n]
  (map #(Integer/parseInt %) (map str (seq (str n)))))

dpsutton19:07:38

is what i've done before

fedreg19:07:52

@dpsutton That’s about what I do. Good, just wanted to make sure I wasn’t missing anything. Thx!

dpsutton19:07:11

probably something better but it hasn't been a bottleneck for my code

ghadi19:07:11

note the call to seq is redudant

ghadi19:07:31

(`map` will coerce things to seqs)

dpsutton19:07:50

but i believe you end up with chars instead of strings of length 1

dpsutton19:07:58

and parseInt requres a string not a char?

ghadi19:07:58

that's map str

dpsutton19:07:12

oh i see. yes you're absolutely correct

dpsutton19:07:28

the first thing map does is ensure a seq

ghadi19:07:29

(map #(Integer/parseInt (str %)) "12345")

fedreg19:07:52

Thank you both!

ghadi19:07:03

i believe @fedreg is using clojurescript, so the call to str is also redundant as well