Fork me on GitHub
#beginners
<
2021-04-21
>
Aron10:04:36

Is #(nth % 1) exactly the same as first?

delaguardo11:04:20

this will be equivalent of second and unlike second it will fail if collection is empty consider this #(nth % 0 nil)

Aron12:04:28

I see, thanks for the correction!

Aron12:04:32

"will fail" means something like an out of bound exception?

delaguardo12:04:54

yes, IndexOutOfBoundsException should be thrown

thanks2 3
Edward Ciafardini13:04:13

Hello. I'm having an issue using slurp. I was following this article to get some experience using it: https://practicalli.github.io/blog/posts/consuming-apis-with-clojure/ When I run the command:

(slurp "")
The result looks like this: 9vTƌE,QZ5,V.&?7WIrrP36틈]H<,ASulbdx[L!ż\tzI:$\r<?:r#F@kk-ד=\tfcZw.f\nNn3{O{\b2R|%{\r)Z4C!tH\\ά5!m£\n%wMN%{ĆX^kCNqd_.J#87S<[tSϦof#:}3a#B\rTci\r%oޅL!=k<_%?\f*'aƊm#wn2zEEzg]$բ|dCUWqٙܟ4D5߱'http://fI.GY \nV;r@&ȱ}Im2Y'8r\fjt7#=@Lp^ (this is only a portion of the output) I tried adding a param for encoding: (slurp "http://www.gutenberg.org/cache/epub/844/pg844.txt" :encoding "UTF-8") It's still giving me the cryptic response.

Alex Miller (Clojure team)13:04:38

I think you're getting a gzipped response

Alex Miller (Clojure team)13:04:04

you may not be able to fix that with slurp

Alex Miller (Clojure team)13:04:08

slurp is a quick and dirty tool, maybe too quick and dirty for this task - you can either use your browser to save that page to disk, then open it from disk with slurp, or use something like https://github.com/dakrone/clj-http as a real http client

Alex Miller (Clojure team)13:04:39

or I guess you could theoretically use the gzip stream stuff built into Java to decode the slurp output probably

Johan Basson14:04:59

Good day. Where can I get a tutorial or guide on how to use the repl?

Dimitar Uzunov14:04:13

its interactive so it is easier to demonstrate with a video than a guide

Karo17:04:26

Hi team, how can I idiomatically replace two maps in this data with other maps that has same keys but different values

[{"key1" "value1"} {"key2" "value2"} {"key3" "value3"} {"key4" "value4"}]
want to update first with {"key1" "value100"} and second {"key1" "value200"} order of maps can be changed so update based on index is not best choice.

delaguardo17:04:20

(into [] (map #(replace-map %))
      [{"key1" "value1"} {"key2" "value2"} {"key3" "value3"} {"key4" "value4"}])
good case for using transducer you need to implement replace-map function which should take a single map from collection and based on condition either leave it intact or change based on your logic

thanks2 3
👍 3
roelof19:04:25

just curious

3
roelof19:04:20

On other languages I had to do a challenge where I had to calculate bowling scores and keep track on spare and strikes . If I have a collection like this : ( 6 4 0 0 10 4 3 0 0 0 0 0 ) How in clojure do I calculate the total score

roelof19:04:00

hmm, that simple. but on a strike the next two scores need to be doubled

Alex Miller (Clojure team)19:04:05

or maybe you need to calculate the bonuses over the top of that - still doable with reduce

roelof19:04:15

yes, I have

Alex Miller (Clojure team)19:04:45

I think you need to track rolls per frame to distinguish strikes and spares though

dpsutton19:04:14

(take 10 (map vector (range) (partition-all 3 1 '( 6 4 0 0 10 4 3 0 0 0 0 0 )))) gets you the 10 frames with frame number and later scores that can affect the score. But impossible to calculate without knowing which 10's are strikes and which are spares

roelof19:04:48

easy a 10 is a strike

roelof19:04:33

and when two seperate numbers are together 10 it is a strike so in my made up it the 6 and 4

roelof19:04:47

so the frames are frame 1 : 6 4 frame 2 : 0 0 frame 3: 10 frame 4: 4 5 frame 5 till 10 : 0 0

dpsutton19:04:26

oh. making this a variable length encoding adds lots of complexity and quite possibly an impossible ambiguity

roelof19:04:03

I know. it was a exercism challenge I tried to do in ruby and haskell

sova-soars-the-sora22:04:12

maybe pre-process the list to create a list of numbers you can simply add. like a raw-score that you derive from the input score sheet.

sova-soars-the-sora22:04:15

you can split the input vector on tens, for example

roelof17:04:48

Maybe, I do not see totally where you are heading to @U3ES97LAC

dpsutton19:04:57

whatever you did in haskell will most likely work almost identically here

roelof19:04:30

I could not solve this one in both 😞

Eric Ihli19:04:02

Is there something like take-through (like take-while but including the next after the predicate return value changes) in Clojure? I see it was https://groups.google.com/g/clojure-dev/c/NaAuBz6SpkY but I can't find it in the docs now. If there's not, then is there a commonly accepted library of "extended utilities" that has it?

madstap20:04:32

Maybe take-upto from https://github.com/weavejester/medley fits the bill

🙏 3
seancorfield20:04:51

dev=> (take-while even? [2 4 6 8 10 11 12 13])
(2 4 6 8 10)
dev=> (into [] (halt-when (complement even?) conj!) [2 4 6 8 10 11 12 13])
[2 4 6 8 10 11]

🤙 3
seancorfield20:04:55

halt-when is a bit strange to use because in the 2-arity version it needs to know about the internals of the transduction, since the accumulator here is a transient.

seancorfield20:04:45

@U050ECB92 ^ this seems odd to me — am I using this correctly?

ghadi20:04:37

Debatable whether this is a bug

ghadi20:04:59

There is a jira for it with more details

seancorfield20:04:10

Ah, OK. Will look it up. Thanks!

ghadi20:04:41

there is a bug IMHO, but it's in into not halt-when

seancorfield20:04:02

Gotcha. Yeah, was just reading that over and digesting it. Is into the only transducer that uses a transient? (I’m kinda surprised if that’s the case)

ghadi20:04:20

it's not the transient that is the issue

ghadi20:04:29

it's the fracturing of the completion arity

ghadi20:04:18

it adds metadata and calls persistent! after the call to transduce

ghadi20:04:27

rather than within the completion arity

seancorfield20:04:15

Ah… yeah, that’s a bit subtle…

ghadi20:04:04

lmk if I can clarify that in the JIRA

seancorfield20:04:08

No, that makes perfect sense now you’ve explained it.

Alexander Kaiser20:04:07

Recommended way for id-based lookups? I want to express the following:

(def input
  {:artists [#:artist{:id 0,
                      :founding-date 2000}],
   :albums [#:album{:id 0,
                    :artist 0,
                    :release-date 2002}]})

(def output
  [#:album{:id 0,
           :artist 0,
           :release-date 2002,
           :artist-years-active-at-release 2}]
  )
One possible solution:
(defn group-by-version [{:keys [artists albums]}]
  (let [artists-by-id (group-by :artist/id artists)]
    (mapv
     (fn[album]
       (->>
        ;; before using first like this i should (spec) check that :artist/id is distinct in artist or use something like only from the tupelo library. Omitted for readability.
        (first (get artists-by-id (album :album/artist)))
        ((fn[artist] (- (:album/release-date album)
                        (:artist/founding-date artist))))
        (assoc album :album/artist-years-active-at-release)
        )
       )
     albums
     ))
  )
(group-by-version input)
However this feels unnecessary verbose and I especially would like to replace the group-by part. Is it better to use spectre or meander for these kinds of operations? Should I structure the data in a different way? Should I transform the data before I do those operations? E.g. with lilactown's new autonormal? I am missing something very obvious here?

Alexander Kaiser21:04:02

Thank you! This helps a lot

Aron20:04:46

If I pass a map with a single key-value pair to a function, how can I destructure the name of the key as a string into a symbol?

seancorfield20:04:42

@ashnur Not sure I’d recommend it but:

dev=> (defn foo [[& [[k v]]]] (str "key=" k ", val=" v))
#'dev/foo
dev=> (foo {:a 1})
"key=:a, val=1"
dev=> (foo {:a 1 :b 2})
"key=:a, val=1"
dev=> 

Aron20:04:14

it's more like (foo {"this_is_backend_string_for_multiple_things" [list of related stuff]})

Aron20:04:51

I just need it more often to find those things and only once to read it backwards, out of the map

seancorfield20:04:45

You mean {v "this_is_backend_string_for_multiple_things"} kind of destructuring?

Aron20:04:23

no, what you wrote is what I need, I just acknowledge that it's weird

Aron20:04:52

probably with practice and experience I would structure my data differently so that it's easy to read it in both directions

seancorfield20:04:23

And then there’s

dev=> (defn foo [{v "foo" w "bar"}] (str "v=" v ", w=" w))
#'dev/foo
dev=> (foo {"foo" 42 "bar" :thirteen})
"v=42, w=:thirteen"
dev=> 
just in case anyone wants to destructure on string keys and rename 🙂

Aron20:04:04

btw, this, what just happened, is almost impossible to do in any other language that's commonly used

Aron20:04:37

if I get some nested object and want to read it both ways, I better store it both ways

Alex Miller (Clojure team)20:04:01

if you know what the string key is, you can also use :strs (analogous to :keys)

Aron20:04:44

I found that in the docs, but there is a list of these and only a number of them are present at a time, not all of them, so it makes more sense to iterate over the maps and read the keys than to filter the maps out based on what keys I can find in nested maps

Aron20:04:10

definitely will use it elsewhere though

Lu20:04:43

Generally, if you provide an input and desired output example you’ll get to the answer you’re looking for much quickly

Aron20:04:34

dunno, I got the perfect answer in 17 minutes, that's beyond any reasonable expectation imho 😄

😄 3
❤️ 3
Aron20:04:07

anyone wants quicker solutions, probably have some other issues too 🙂

Alexander Kaiser21:04:37

@roelof not elegant but maybe a starting point:

(loop
    [spare-counter 0
     strike-counter 0
     scores '(6 4  0 0 10 4 3 0 0 0 0 0 0 8 9)]

  (let [round-result
        (if
         (= 10 (first scores))
          :spare-on-first
          (cond
            (= 10 (second scores))
            :spare-on-second
            (<= 10 (reduce + (take 2 scores)))
            :strike
            )

          )]
    (if
        (or (and (= round-result :spare-on-first)
                 (< (count scores) 1)
                 )
            (< (count scores) 2)
            )
      {:spare-counter spare-counter
       :strike-counter strike-counter}
      (recur ({:spare-on-first (inc spare-counter)
               :spare-on-second (inc spare-counter)
               :strike spare-counter
               nil spare-counter}
              round-result)
             ({:spare-on-first strike-counter
               :spare-on-second strike-counter
               :strike (inc strike-counter)
               nil strike-counter}
              round-result)
             ({:spare-on-first (rest scores)
               :spare-on-second (nthrest scores 2)
               :strike (nthrest scores 2)
               nil (nthrest scores 2)
               }
              round-result)
             )))
  )

Alexander Kaiser21:04:42

a bit cleaner

(defn frame-length[scores]
  (loop
      [frames []
       scores scores]

    (let
        [round-length
         (if (= (first scores) 10)
           1
           2)
         new-scores (nthrest scores round-length)
         new-frames (conj frames (take round-length scores))
         ]

      (if
          (= (count new-scores) 0)
        new-frames
        (recur
         new-frames
         new-scores
         )))
    )
  )


(def scores '(6 4  0 0 10 4 3 0 0 0 0 0 0 8 9 10))

(frame-length scores)
;;spares
(count (filter #(contains? (set %) 10) (frame-length scores)))
;;strikes
(count (filter (fn[f] (and (<= 10 (reduce + f))
                           (not (contains? (set f) 10))))
               (frame-length scores)))

madstap22:04:55

@roelofw I gave it a shot. Since there is quite a bit of state to care about, I modeled the current state as a map, and put all the rules in a reducing function called roll with arity [state throw] => next-state. The function to get the final state then becomes simply:

(defn game [throws]
  (reduce roll empty-state throws))
A nice thing about this approach is that I can use reductions to get a vector of all the states, which makes it easy to debug. This is my attempt: https://gist.github.com/madstap/d9eb24395841f5a2ee2292ccbd0baec4

Lucas Garcia22:04:20

Hello y'all! I just started learning clojure and I found some resources about the language, but I was looking for something more focused on web development. Do you have any recommendations? Thanks in advance!

seancorfield22:04:57

Hi @lucas.garcia Have you taken a look at Dmitri Sotnikov’s book on Web Development with Clojure/Script?

Lucas Garcia12:04:48

Hi, @U04V70XH6! Thanks for response

Lucas Garcia12:04:19

I'm checking Dmitri Sotnikov's book right now

Lucas Garcia13:04:24

I don't know much about web applications, but I have experience with mobile application with flutter and kotlin.

Lucas Garcia13:04:18

I wanted something that could look for when I face any problem.

seancorfield22:04:10

There’s a 3rd in beta at the moment I believe.

seancorfield22:04:48

It’s not exactly beginner material, but it will give you an idea of the scope of web development using Clojure on the backend and ClojureScript on the frontend.

seancorfield22:04:39

If you just want to see a beginner-level example of a (server-side) Clojure web app, I generally point beginners at https://github.com/seancorfield/usermanager-example — and there’s a version using different libraries linked from the README.

seancorfield22:04:25

It also often helps us point people at appropriate material if they give us a bit of information about their background (amount of programming overall, what languages/tech they’ve used, etc).