Fork me on GitHub
#beginners
<
2023-01-21
>
noob.clj18:01:20

So in book “Programming Clojure” I really like the example of converting indexOfAny into clojure. However I am not sure how can we more optimize the algorithm of it. For instance the Java code can be further optimized using HashSet for check and then it’ll pretty much return the first character it finds and not go through the whole array, so the number of iterations will be the index of first character found. But in the clojure approach the method index-filter will check all the elements. For small strings it should be fine, but I can see that it can be slow for very long strings. Is there a way we can optimize index-filter to return a lazily evaluated list?

dpsutton19:01:27

can you give a bit more context?

dpsutton19:01:43

like the source of indexOfAny?

noob.clj19:01:52

Ohh sure Optimized indexOfAny from Java:

public static int indexOfAny(String str, char[] searchChars) {
        if (isEmpty(str) || searchChars == null || searchChars.length == 0) {
            return -1;
        }
        Set<Character> searchSet = new HashSet<>();
        for(char ch: searchChars)
            searchSet.add(ch);

        for(int i=0; i<str.length(); i++) {
            char ch = str.charAt(i);
            if(searchSet.contains(ch))
                return i;
        }
        return -1;
    }
index-of-any in clojure
(defn indexed [coll] (map-indexed vector coll))

(defn index-filter [pred coll]
  (when pred
    (for [[idx elt] (indexed coll) :when (pred elt)] idx)))

(defn index-of-any [pred coll]
  (first (index-filter pred coll)))

dpsutton19:01:41

index-filter uses for. and (doc for) says that it > yields a lazy sequence So we don’t necessarily run through the whole string

noob.clj19:01:06

ohh my bad, I didn’t realize that for does lazy evaluation. Thanks a lot for clarifying 🙂

dpsutton19:01:18

You should write versions that use loop and reduce as an exercise. And those let you more strongly control the execution

noob.clj19:01:05

💡 Good idea, I can try that. thanks3

Mendel19:01:09

Can anyone enlighten me what I'm missing with lazySeq, it seems like it doesn't want to compute 😞

(def common-hex (doall (->> (find-overlapping-colors xkcd-colors html-colors :hex)
                            (map (fn [c] (get-colordata-by-color (concat xkcd-colors html-colors) c)))
                            (map (fn [c] [:div {:style {:width 100
                                                        :height 100
                                                        :background-color (:hex (first c))}}])))))
;; => #'core-color-game/common-hex

(type common-hex)
;; => clojure.lang.LazySeq
(type (first common-hex))
;; => clojure.lang.PersistentVector
(type (doall common-hex))
;; => clojure.lang.LazySeq

seancorfield19:01:32

doall forces execution but doesn't change the type: it's still a LazySeq -- it's just a fully-realized LazySeq.

Mendel19:01:10

oh derp, thanks

seancorfield19:01:09

If you don't want it to be lazy, use mapv instead of map in the last expression (and then you won't need doall) -- and you'll get a vector.

Mendel19:01:48

Thanks, I've should've read more closely. In my mind it should've been working just like calling .toList on an enumerable in c# or something

seancorfield19:01:54

Or look at transducers which would give you:

(def common-hex (into []
                      (comp (map .. get-colordata-by-color ..)
                            (map .. [:div .. ] .. ))
                      (find-overlapping...)))

🙏 2
Hippolyte23:01:42

Hello, I'm trying to extend an interface, and to set a private field named "site". Can someone point me the correct way of doing this, I've tried to use a reify and with a proxy but with no success.

(proxy [PageProcessor] []
     (set! (.this -site) Site/me)
     (^Site getSite []
      (.this site)))
...
the java equivalent is
public class GithubRepoPageProcessor implements PageProcessor {

    private Site site = ();
...

Gerome17:01:20

Is there a particular reason, you’re trying to extend an interface? Do you really need to do this?

didibus18:01:54

Interfaces dont have fields. In your case it's the class GithubRepoPageProcessor that has a field, not the interface PageProcessor.

didibus19:01:17

If you want state with proxy, you would use a closure such as:

(let [state (atom {})]
  (proxy ...))
And inside the method implementations of proxy you can read/write to the state atom