Fork me on GitHub

Is there something in core like cond-> that threads the expression value through the test(s) too? I.e. I want to do something like this:

(cond->-> (big-operation-maybe-returns-future!)
  future? deref)


Best alternative I could come up with is:

(let [result (big-operation-maybe-results-future!)
      result (if (future? result) @result result)]
  ;; ...


could also use cond-> there, but that seems a bit forced


No, but we released a small library at work that has condp-> that does this…


It has condq (a unary version of condp) and condp-> / condp->> to match cond-> / cond->> but thread the expression through the predicate (plus other stuff).

Eric Ihli02:04:16

What's the idiomatic way to do the following. I have a huge list of text files I need to process efficiently. Can't keep everything in memory. So I'm going with transducers.

  (comp (remove #(.isDirectory %))
        (map slurp)
        (map #(string/split % #"[\n+\?\.]"))
        (map (partial map #(string/split % #" +")))
        (map (partial map (partial map syllabify-word)))
        (map (partial map (partial map (partial map process-syllable)))))
  (file-seq (io/file "data-directory")))
What's going on is each step of the transduction creates a new level of a nested sequence. I start with a file, split that on newlines, then split each line of each file on spaces, then split each word of each line of each file into syllables... etc... The nesting gets confusing to reason about, hard to code complicated transformations for. If I could have everything in memory at one time, I'd just have a flatten step somewhere in there. Is there some simplifying alternative that I'm not seeing? Edit: I may have just seen an obvious answer. I can combine most of those into a process-file function which can flatten and do whatever the heck it wants since it will have at most 1 file in memory at a time. Something like:
(defn process-file
  (->> text
       (#(string/split % #"[\n+\?\.]"))
       (mapcat #(string/split % #" +"))
       (mapcat syllabify-word)
       (map process-syllable)))

  (comp (remove #(.isDirectory %))
        (map slurp)
        (map process-file))
  (file-seq (io/file "data-dir")))

👍 5

Trying to use luminus web framework. After checking the password against the password that's been hashed in the db with exactly do you tell buddy that the user is now logged in and authenticated?


I don't use Luminus or buddy, but usually you do this by setting a cookie with a session id.

Prabu Rajan08:04:10

I have a map of maps and I want to lookup by a value (value of a particular entry in the inner map), assuming the value is unique and return the inner map and its key as a vector. Is there a more optimal solution for this?

(defn get-user-by-email [users email]
  (->> (filter #(= email (::email (last %))) (into [] users))

(get-user-by-email {:one {::first-name "Agatha" ::last-name "Christie" ::email ""}
           :two {::first-name "Charles" ::last-name "Dickens" ::email ""}}


Linear search on a collection usually indicates that you ought to look into making your input data more amenable to lookups. For instance, you could here turn the input map into a map of email -> user:

user=> (def users-by-email
         (into {}
           (map (juxt ::email identity))
           [{::id :one ::first-name "Agatha" ::last-name "Christie" ::email ""}
            {::id :two ::first-name "Charles" ::last-name "Dickens" ::email ""}]))
user=> (users-by-email "")
#:user{:id :two, :first-name "Charles", :last-name "Dickens", :email ""}


See also But if you absolutely need to do a linear search, using reduce + reduced is probably the fastest option:


use some

(defn get-user-by-email [users email]
  (some #(and (= email (::email (last %))) %) users))

Prabu Rajan15:04:00

@U4ZDX466T Yes, in most cases I want to lookup the user details by user-id, but in some cases I dont know the id and need to lookup by email and hence this

Prabu Rajan15:04:18

@U0ZK920CQ Thanks. I am a bit of a newbie. I am wondering how some works on a map of maps. Does it automatically convert the map into a vector of [:key val] ?


Hmm, let's test it in a REPL

Prabu Rajan17:04:09

Yes, it looks like that. When I did a log of %, I get a vector of the key-value pairs for each entry in the users map. So ‘some’ converts a map of maps into a vector of vectors automatically before applying the predicate

(defn get-user-by-email [users email]
  (some #(-> (log %) (and (= email (::email (last %))) %))

(get-user-by-email {:one {::first-name "Agatha" ::last-name "Christie" ::email ""}
           :two {::first-name "Charles" ::last-name "Dickens" ::email ""}}


[:one{:first-name Agatha, :last-name Christie, :email }]
[:two{:first-name Charles, :last-name Dickens, :email }]
=> [:two{:first-name "Charles", :last-name "Dickens", :email ""}]

Prabu Rajan17:04:05

Thanks everyone for your help


is there just a straight forward way to concat an element to a list?


conj adds to the head, I want it on the tail, I don’t care if it’s slow


concat '() [element] seems dumb


is there a reason you can't use a vector?


that syntax is less dumb than what you are doing algorithmically


and yeah, usually a vector is the right answer if you want to add at the end


also - why a list? they are very rarely useful


and concat doesn't return one anyway

user=> (type (concat '(1 2) '(3 4)))


I need it because I am writing a parser


that distinguishes lists from vectors


I could perhaps build it as a vector and when I see the ) convert it to a list

👍 2

perhaps it distinguishes seqs from vectors? because concat doesn't return a list


and yeah, abstracting the parser internal representation from the concrete clojure data type sounds wise


but how? A sentinel value at the head of the vector to say if it’s ‘actually’ a vector? That still seems a bit janky, to me


{:data-type :list :contents []}


that plus some multi-methods that dispatch on :data-type should get you pretty far


alternatively, you can use metadata, but I tend to prefer keeping things explicit and visible


yeah, fair, I already have my tokenizer like that