*Simple question : Why does this function throw an exception when evaluated ? *
In the case where there is a duplicate in the string , there is a Class cast exception thrown upon finding the duplicate.
In the case where the string has no duplicates, a NullPointerException is thrown.
*The Code *
(defn first-duplicate-char [str-in]
(loop [list-Rem (seq str-in) set-Seen (set [])]
(print (type list-Rem) " " list-Rem (next list-Rem) "\n")
(if (= 0 (count str-in))
nil
(if (some #(= (first list-Rem) %) set-Seen)
(first list-Rem)
(recur
(seq (next list-Rem))
(conj set-Seen (first list-Rem)))))))
Your problem is that (= 0 (count str-in)) never changes, so you eventually try to call first on nil. [EDIT: I'm wrong, your code actually works as is -- that if statement is just a no-op. I hope you enjoy the rest of this answer anyway.]
Instead, you should be calling next (not rest) on list-Rem in the recur and using list-Rem directly in the if test, using the property of next that returns nil for an empty seq. Here's how I would rewrite your code:
(defn first-duplicate [in]
(loop [seen #{}
remain (seq in)]
(when-let [[head & tail] remain]
(if (contains? seen head)
head
(recur (conj seen head) tail)))))
Changes:
lowercasing names
no need to call seq on the output of next or rest
with sets, contains? (check for existence of key) is faster than some (run a predicate on elements until something yields a truthy value)
set literal
using when to return nil on test failure
using when-let to destructure and bind first char and rest
Stylistic changes:
names changed to be less specific (not restricted to strings, for instance)
change order of loop locals so that recur looks more like structural recursion
put loop locals on separate lines
Related
To preface this, I'm very new to Clojure. I was wondering why I'm getting a ClassCastExpection on this piece of code. I've looked at it and syntactically and logically it looks correct?
Clojure Code:
; (load-file "cje842asg1.clj")
(def lstnum '(76 85 71))
; 2a
(defn sum [list] (
(if (empty? list)
0
(+ (first list (sum (rest list))))
)
)
)
; if empty return zero, else add the first num in list and pass in the
; rest.
(sum lstnum)
Any help is appreciated.
The code has 2 separate errors.
The first is calling (first list (sum (rest list))) which is calling first with 2 arguments when you meant to make the second part the second argument to +.
The other one leading to the actual exception is the extra () around the function body. Note the ((if ...)) which means you are trying to call whatever the if returns as a function. In this case it is returning a number, leading to the class java.lang.Long cannot be cast to class clojure.lang.IFn error.
The corrected version would be
(defn sum [list]
(if (empty? list)
0
(+ (first list)
(sum (rest list)))))
Moving the arguments to + into separate lines makes it easier to read in this case (IMHO).
I have tried to make it unnecessary to fully understand the code, so read the whole question first, then dig into the code if necessary.
I'm trying to make a macro for pattern matching.
It works by taking a list in which the first element is type of matching to be performed
Example: the first element in the list is "cons"; the macro would call a cons matching function.
A matching function takes an object and a function, calls the function with the matched value. With the cons matcher, it would call the function with the head and tail of the list.
I used a "num" matcher for testing. It's basically an identity matcher, so it could be nested inside itself arbitrarily, as I did below.
;a macro to make debugging easier
(defmacro log [item] `(do (print ~(join [(str item) ": "])) (println ~item)))
(defn make-pattern-matcher-iter [result bindings-queue]
(println "starting next iteration")
(log bindings-queue)
(if (first bindings-queue) (println "bindings-queue does contain an element") nil)
(if (first bindings-queue)
(let [[next-symbol pattern] (first bindings-queue)
pattern-name (first pattern)
pattern-items (next pattern)
pattern-matching-function (prepend-symbol "match-" pattern-name)
gensyms-attached-to-subpatterns (map (fn [pattern]
(if (symbol? pattern)
pattern
`(~(gensym "matchbinding") ~pattern)))
pattern-items)
all-bound-symbols (map (fn [sym]
(if (symbol? sym) sym (first sym)))
gensyms-attached-to-subpatterns)
gensyms-subpattern-pairs (filter list? gensyms-attached-to-subpatterns)
rest-of-bindings-queue (next bindings-queue)
updated-bindings-queue (concat rest-of-bindings-queue
gensyms-subpattern-pairs)
subpatterns (map second gensyms-subpattern-pairs)]
(log next-symbol)
(log all-bound-symbols)
(log updated-bindings-queue)
(log gensyms-attached-to-subpatterns)
(log gensyms-subpattern-pairs)
(log subpatterns)
`(~pattern-matching-function
~next-symbol
(fn [~#all-bound-symbols] ~(make-pattern-matcher-iter result updated-bindings-queue))))
result))
(defn make-pattern-matcher [object pattern result] (make-pattern-matcher-iter result [[object pattern]]))
(defn match-num [x f]
(if (number? x) (f x) nil))
(def this-m (make-pattern-matcher-iter '(+ x y) [['object '(pair x y)]]))
(def this-n (make-pattern-matcher '15 '(num (num z)) 'z))
(= this-n this-m)
(defmacro bind-match [object pattern result] (make-pattern-matcher object pattern result))
(bind-match 15 (num (num z)) z)
The problem is that the macro isn't properly binding "z"
the log gives on the second iteration:
gensyms-attached-to-subpatterns: ((matchbinding8210 (num z)))
gensyms-subpattern-pairs: ()
there are other log messages, but these seem to be the problem.
Take a look at how gensyms-subpattern-pairs is calculated. In the let block it says:
gensyms-subpattern-pairs (filter list? gensyms-attached-to-subpatterns)
this should take out everything but lists, which is all there is, so it shouldn't take out anything.
The filter seems to be too aggressive. Why?
As you noted, the elements of gensyms-attached-to-subpatterns are not IPersistentLists, but rather Conses. Sanity check:
(contains? (supers clojure.lang.Cons) clojure.lang.IPersistentList)
;=> false
So it looks like you'll need to use some other check than list?.
I am having a hard time tracking down a stackoverflow error produced by my clojure implementation of the Bron-Kerbosch algorithm.
Below is my implementation of the algorithm itself, and here is a link to a SSCCE outlining the issue http://pastebin.com/gtpTT4B4.
(defn Bron-Kerbosch [r p x graph cliques]
;(println (str "R:" r " P:" p " X:" x " Clq:" cliques))
(cond (and (empty? p) (empty? x)) (concat cliques r)
:else
(let [neigh (neighV graph (dec (count p)))]
(loop [loop-clq '(cliques)
loop-cnt (dec (count p))
loop-p '(p)
loop-x '(x)]
(cond (= -1 loop-cnt) loop-clq
:else
(recur (concat loop-clq
(Bron-Kerbosch (concat r loop-cnt)
(concat p neigh)
(filter (set x) neigh)
graph cliques))
(dec loop-cnt)
(filter (set p) loop-cnt)
(concat x loop-cnt)))))))
I would have to assume that the issue obviously lies within one of my two bootstrap conditions (cond (and (empty? p) (empty? x)) and (cond (= -1 loop-cnt) because the function algorithm is recursive.
Though this assumes that I am building the lists x r p correctly. Judging by the output of the commented out print statement (cliques is always printed as an EmptyList) I assume that my list comprehension might also be the issue.
Along the same lines, the other issue I can somewhat see is that I am not actually calling the algorithm properly in the BK-Call function (in the SSCCEE).
My overall question is what is causing this? Though this is somewhat too open, another question that might lead me to my answer is how I might go about using the print statement on the first line.
When the print statement is uncommented it produces the output
R:clojure.lang.LazySeq#2044e0b9 P:clojure.lang.LazySeq#7f9700a5 X:clojure.lang.LazySeq#1 Clq:clojure.lang.PersistentList$EmptyList#1
I assume that if I could see that x r p are at each call I might be able to see where the algorithm is going wrong.
Can anyone point me in the right direction?
EDIT: The neighV function from the SSCCE
(defn neighV [graph nodenum]
(let [ret-list (for [i (range (count graph)) :when (contains? (graph i) nodenum)] i)]
ret-list))
EDIT2: Noisesmith's answers had gotten me closer to the solution and made sense to me. I wrapped all of my concat in doall. After trying to call the function again I was getting "Cannot cast Long to Seq" errors, I figured that these stemmed from trying to concat loop-cnt onto lists in the function
fptests.core> (BK-Call (sanity1))
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:505)
fptests.core> (concat 1 '(2 3))
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:505)
So I then wrapped each loop-cnt in a '() to turn it into a list before it is concat
fptests.core> (concat '(1) '(2 3))
(1 2 3)
Which, after I made all of these changes, I ended back at my stack overflow.. Here is the new Bron-Kerbosch function with all of the edits. I guess I now have the same questions as I did before..
Though the new ones are, did I implement that changes that I should have correctly, does the usage of '() make sense to fix the issue that came up after implementing noisesmith's changes?
(defn Bron-Kerbosch1 [r p x graph cliques]
(cond (and (empty? p) (empty? x)) (doall (concat cliques r))
:else
(let [neigh (neighV graph (dec (count p)))]
(loop [loop-clq '(cliques)
loop-cnt (dec (count p))
loop-p '(p)
loop-x '(x)]
(cond (= -1 loop-cnt) loop-clq
:else
(recur (doall (concat loop-clq
(Bron-Kerbosch1 (doall (concat r '(loop-cnt)))
(doall (concat p neigh))
(filter (set x) neigh)
graph cliques)))
(dec loop-cnt)
(filter (set p) '(loop-cnt))
(doall (concat x '(loop-cnt)))))))))
EDIT3: After patiently waiting for my prn statements to stop (not sure why I put them in when I knew it was in a SO) I found that most if not all statements printed were along the lines of
"R:" (loop-cnt loop-cnt loop-cnt loop-cnt loop-cnt loop-cnt loop-cnt ...)
"P:" (range (count graph) 0 2 3) " X:" () " Clq:" ()
After inspecting this some I realized that I have not been recursively calling the function properly. I have been union'ing items to P instead of removing them. This causes P to continuously grow. This is most likely the cause of my stack overflow. Though there are still some issues. I still am creating a stackoverflow, yet again.
Once I fixed my issue of continuing to union to P my issue is that when I concat loop-cnt it is not, I guess to say, evaluated to a value but it stays as a variable name loop-cnt. I suspect that my stack overflow now lies with my bootstrap condition not being met because it cannot be met if loop-cnt is not evaluated to a number.
So I think my issue now lies with concat loop-cnt to a list as a number and not a variable.
concat is lazy. Recursive calls that build concat on top of concat, without realizing any of the prior layers of laziness, each add to the size of the stack of calls that will be needed to realize the lazy-seq.
Does this concatenation need to be lazy at all? If not, wrap the calls to concat in calls to doall. This will make the concatenation eager, which reduces the size of the call stack needed to realize the final result, and thus eliminating the StackOverflowError.
Also, the correct way to print a lazy-seq and see the contents is prn, you can use pr-str to get the form of the value that pr or prn would use as a string, if needed.
You are misusing quoted lists, I think.
For example, in (defn Bron-Kerbosch1 [ ... ] ... ), '(cliques) evaluates to a list containing the symbol cliques, not to a list containing the argument cliques as its one element. You want (list cliques) for that.
Similar cases abound.
I'm writing a loop which creates a map from string data in a vector. In each iteration I take the last item in the vector, construct a key and a value from it, associate those with the map and then pop the item just logged to the map off of the vector. As long as the vector still has items in it, this process should keep repeating until the vector is empty and the map is full.
The function reads as follows:
(defn map-builder
"Transforms the vector of waterfalls into a map of waterfalls."
[input]
(loop [waterfall-db {}
vectorized-db input]
(let [key-str (last vectorized-db)]
key (->> key-str
(re-seq #"[0-9]+")
keyword)
val (subs key-str (+ 2 (.indexOf key-str ":"))))
(assoc waterfall-db key val)
(pop vectorized-db)
(if (> (count vectorized-db) 0)
(recur waterfall-db vectorized-db) waterfall-db)))
The program compiles, but seems to be looping infinitely. I did a test making the loop quit after one iteration, and it returned an empty map (it should have had one item in it). Clearly I'm improperly associating items with the map, and it makes me think I must be disassociating items with the vector improperly as well. I can't see where I'm going wrong though—have I scoped my locals improperly?
In clojure, data structures don't change in-place: new data-structure values are calculated from old ones.
In your code, you do (pop vectorized-db) with the intention of
popping the last element out. Clojure's pop doesn't work like this,
but computes a new vector with the same elements as vectorized-db
but the last one.
The same applies to (assoc waterfal-db key val).
What you have to do is pass the new values in the recur call. The code (which I haven't tested because I don't have an example of what it is supposed to do) transforms to:
(defn map-builder
"Transforms the vector of waterfalls into a map of waterfalls."
[input]
(loop [waterfall-db {}
vectorized-db input]
(if (empty? vectorized-db)
waterfall-db
(let [key-str (last vectorized-db)
key (->> key-str
(re-seq #"[0-9]+")
keyword)
val (subs key-str (+ 2 (.indexOf key-str ":")))]
(recur (assoc waterfall-db key val) (pop vectorized-db))))))
The answer posted by Juan Manuel is correct, but you might consider building your map via into which is more straightforward:
(defn- make-kv [s]
(let [key (->> s (re-seq #"[0-9]+") first keyword)
val (-> s (.split ":") second string/trim)]
[key val]))
(defn map-builder [v]
(into {} (map make-kv v)))
How do I get the index of any of the elements on a list of strings as so:
(list "a" "b" "c")
For example, (function "a") would have to return 0, (function "b") 1, (function "c") 2 and so on.
and... will it be better to use any other type of collection if dealing with a very long list of data?
Christian Berg's answer is fine. Also it is possible to just fall back on Java's indexOf method of class String:
(.indexOf (apply str (list "a" "b" "c")) "c")
; => 2
Of course, this will only work with lists (or more general, seqs) of strings (of length 1) or characters.
A more general approach would be:
(defn index-of [e coll] (first (keep-indexed #(if (= e %2) %1) coll)))
More idiomatic would be to lazily return all indexes and only ask for the ones you need:
(defn indexes-of [e coll] (keep-indexed #(if (= e %2) %1) coll))
(first (indexes-of "a" (list "a" "a" "b"))) ;; => 0
I'm not sure I understand your question. Do you want the nth letter of each of the strings in a list? That could be accomplished like this:
(map #(nth % 1) (list "abc" "def" "ghi"))
The result is:
(\b \e \h)
Update
After reading your comment on my initial answer, I assume your question is "How do I find the index (position) of a search string in a list?"
One possibility is to search for the string from the beginning of the list and count all the entries you have to skip:
(defn index-of [item coll]
(count (take-while (partial not= item) coll)))
Example: (index-of "b" (list "a" "b" "c")) returns 1.
If you have to do a lot of look-ups, it might be more efficient to construct a hash-map of all strings and their indices:
(def my-list (list "a" "b" "c"))
(def index-map (zipmap my-list (range)))
(index-map "b") ;; returns 1
Note that with the above definitions, when there are duplicate entries in the list index-of will return the first index, while index-map will return the last.
You can use the Java .indexOf method reliably for strings and vectors, but not for lists. This solution should work for all collections, I think:
(defn index-of
"Clojure doesn't have an index-of function. The Java .indexOf method
works reliably for vectors and strings, but not for lists. This solution
works for all three."
[item coll]
(let [v (if
(or (vector? coll) (string? coll))
coll
(apply vector coll))]
(.indexOf coll item)))
Do you mean, how do you get the nth element of a list?
For example, if you want to get the 2nd element on the list (with zero-based index):
(nth (list "a" "b" "c") 2)
yields
"c"
Cat-skinning is fun. Here's a low-level approach.
(defn index-of
([item coll]
(index-of item coll 0))
([item coll from-idx]
(loop [idx from-idx coll (seq (drop from-idx coll))]
(if coll
(if (= item (first coll))
idx
(recur (inc idx) (next coll)))
-1))))
This is a Lispy answer, I suspect those expert in Clojure could do it better:
(defn position
"Returns the position of elt in this list, or nil if not present"
([list elt n]
(cond
(empty? list) nil
(= (first list) elt) n
true (position (rest list) elt (inc n))))
([list elt]
(position list elt 0)))
You seem to want to use the nth function.
From the docs for that function:
clojure.core/nth
([coll index] [coll index not-found])
Returns the value at the index. get returns nil if index out of
bounds, nth throws an exception unless not-found is supplied. nth
also works for strings, Java arrays, regex Matchers and Lists, and,
in O(n) time, for sequences.
That last clause means that in practice, nth is slower for elements "farther off" in sequences, with no guarantee to work quicker for collections that in principle support faster access (~ O(n)) to indexed elements. For (clojure) sequences, this makes sense; the clojure seq API is based on the linked-list API and in a linked list, you can only access the nth item by traversing every item before it. Keeping that restriction is what makes concrete list implementations interchangeable with lazy sequences.
Clojure collection access functions are generally designed this way; functions that do have significantly better access times on specific collections have separate names and cannot be used "by accident" on slower collections.
As an example of a collection type that supports fast "random" access to items, clojure vectors are callable; (vector-collection index-number) yields the item at index index-number - and note that clojure seqs are not callable.
I know this question has been answered a million time but here is a recursive solution that leverages deconstructing.
(defn index-of-coll
([coll elm]
(index-of-coll coll elm 0))
([[first & rest :as coll] elm idx]
(cond (empty? coll) -1
(= first elm) idx
:else (recur rest elm (inc idx)))))
(defn index-of [item items]
(or (last (first (filter (fn [x] (= (first x) item))
(map list items (range (count items))))))
-1))
seems to work - but I only have like three items in my list