Clojure: How to count occurrences in a list? - clojure

I'm still pretty new to clojure, so I apologize if this a bit trivial. Basically, the issue is in the "then" part of the if statement: (if (symbol? (first slist)).
;counts the number of occurences of
(defn count-occurrences [s slist]
(if (empty? slist)
0
(if (symbol? (first slist))
(if (= (first slist) s)
(+ 1 (count-occurrences s (rest slist)))
(+ 0 (count-occurrences s (rest slist))))
(count-occurrences s (first slist))))) ;Problem on this line
(println (count-occurrences 'x '((f x) y (((x z) x)))))

To count elements in a nested list, you could try this function:
(defn count-occurrences [s slist]
(->> slist
flatten
(filter #{s})
count))
Test:
user> (count-occurrences 'x '((f x) y (((x z) x))))
;; => 3
user> (count-occurrences 'y '((f x) y (((x z) x))))
;; => 1
user> (count-occurrences 'z '((f x) y (((x z) x))))
;; => 1

As Diego Basch commented, the skeleton of your algorithm ought to be
(defn count-occurrences [s slist]
(+ (count-occurrencies s (first slist))
(count-occurrencies s (rest slist))))
... which has one or two little problems:
It never terminates.
It doesn't deal with a symbol.
It doesn't deal with an empty list.
slist might not be a list, and eventually, through first calls,
won't be.
How do we deal with these problems?
First, test whether were dealing with a symbol.
If we aren't, assume it's a list and test whether it's empty.
If not, apply the skeleton recursion.
... giving us something like this:
(defn count-occurrences [s x]
(if (symbol? x)
(if (= x s) 1 0)
(if (empty? x)
0
(+ (count-occurrences s (first x))
(count-occurrences s (rest x))))))
... which works:
(count-occurrences 'x '((f x) y (((x z) x))))
;3
This solution has several problems (which you'll come to appreciate) that make Mark's answer superior in practice. However, if you're trying to get to grips with recursion, this will do nicely.

Related

Clojure: Implementing the some function

I'm new to clojure and tried to implement the some function (for some specific tests):
(my-some even? [1 2 3 4]) => true
(my-some #{3 4} [1 2 3 4]) => 3
(my-some zero? [1 2 3 4]) => nil
That's what I came up with so far:
(defn my-some [f x]
(loop [[y & t] x]
(if (empty? t) nil
(if (f y)
(f y)
(recur t)))))
I could imagine there are more idiomatic approaches.
Any suggestions?
Firstly, you have a bug: [[y & t] x] destructures x, but the following empty? check on t means you are ignoring the last element in the sequence. You can see this with
(my-some even? [2])
=> nil
You can replace (if (empty? x) nil (else-form)) with when and seq:
(when (seq x) ...)
you can then use first and next to deconstruct the sequence:
(defn my-some [f x]
(when (seq x)
(if (f (first x))
(f (first x))
(recur f (rest x)))))
the call to recur is then back into my-some so you need to pass the predicate f.
you can replace (if x x (else ....)) with (or x (else ...)):
(defn my-some [f x]
(when (seq x)
(or (f (first x)) (recur f (next x)))))
you can compare this with the implementation of some

4clojure: set-intersection, recursive lambda

I am attempting to write a recursive lambda function (accepting two arguments) that finds the intersection between two (potentially) unsorted sets. Here is the code, which I believe most will find straight forward:
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out))))
(inner (rest x) y (cons (first x) out))
(inner a b '[])
)
I hope to use this lambda function intersection in place of the underscore _ that follows:
(= (__ #{0 1 2 3} #{2 3 4 5}) #{2 3})
However, this code fails to compile, insisting that Java is Unable to resolve symbol: inner in this context...
Any suggestions?
source: http://www.4clojure.com/problem/81
You could try :
#(set (filter %1 %2))
Since sets are functions (see another useful example there). The syntax with %1 and %2 is the same as writing :
(fn [s1 s2] (set (filter s1 s2)))
Or even more succinctly :
(comp set filter)
Regarding the inner error, you simply misplaced the parens (but I don't really see the logic otherwise) :
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out)))
(inner (rest x) y (cons (first x) out))
(inner a b '[])))
If you insist on building the set manually (which I did not so long ago), you could end up with something like that :
(fn [s1 s2]
(reduce #(if (contains? s2 %2) (conj %1 %2) %1) #{} s1))
But really the first solution is the most elegant.

Clojure : function returns nil rather an evaluated expression

I have written a function that sums the members of a list. Pretty straightforward, newbie stuff, but for some reason it returns nil, and I am at a loss as to why: this should be a no-brainer. The implementation and function call follow.
The implementation:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 2)
(+ (first x) (first (rest x)) total))
(if (= (count x) 1)
(+ (first x) total))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
The call to the function:
(println "our total is: " (add-list-members '(2 23 33 14 33 134 9000 98993)))
Meanwhile, I have a debugging version with print statements added, and I have been able to verify that the implementation works as it should.
Debugging version:
(defn add-list-members-debug
([x] (add-list-members-debug x 0))
([x total]
(println ">>> our list now: " x)
(println ">>> our total now: " total)
(if (= (count x) 2)
(println "outcome 2 : " (+ (first x) (first (rest x)) total)))
(if (= (count x) 1)
(println "outcome 1 : " (+ (first x) total)))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
Call to debugging version:
(add-list-members-debug '(2 23 33 14 33 134 9000 98993))
The development tools I am using are Vim plugged into the Leiningen REPL. Any hints about what I'm doing wrong here would be most appreciated.
You used if in a wrong way. Consider the following code: I intentionally simplified the code to make it clear what happens.
(defn xxx [v]
(if (= (count v) 1) "one")
(if (= (count v) 2) "two")
(if (> (count v) 2) "more"))
What happens if you run (xxx [1])? Perhaps you expect the code will return "one", however, it returns nil. Why?
Function returns value of its last expression, in this case, the last line (if (> (count v) 2) "more"). If you pass [1], the first if expression returns "one", which is ignored. The second if will return nil, which is also ignored. The third and the last will return nil, which is the return value of the function.
Perhaps the simplest way to compute sum of elements is:
(defn add-elements [xs] (apply + xs))
or
(defn add-elements [xs] (reduce + xs))
Your code can be reimplemented in much simpler way:
(defn add-elements
([xs] (add-elements xs 0))
([xs total] (if (empty? xs) total
(recur (rest xs) (+ total (first xs))))))
The parentheses are wrong, or at least suboptimal, and you have no base case that returns total. (About the parentheses: Your indentation, which is correct given the parentheses, shows this: Each if is on the same level; none of them are in the "else" position.) Here's one correct version:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 0)
total
(if (= (count x) 2)
(+ (first x) (first (rest x)) total)
(if (= (count x) 1)
(+ (first x) total)
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total))))))))
You get nil as the return value because when the last if test fails, it goes to the else clause, which in this case is an empty end of a list, i.e. nil.
However, the multiple ifs can be replaced with one cond. You can also use ffirst for (first (first, fnext instead of (first (rest, and nnext instead of (rest (rest. It would also be more idiomatic to use a predicate such as empty? instead of checking for count equal to 0; I used count for the base case simply to maintain the parallel with your existing code. The simplest version might be:
(defn add-list-members [x] (apply + x))
You could also use reduce for a very simple version. You may just have wanted to experiment with recur, though.
(Well, you could do it without using the embedded else clauses, as in your original, but I wouldn't recomment it, and you still need the empty sequence base case. When you put multiple separate expressions in an function definition, each one of them always gets executed. This is inefficient and, I feel, error prone. Using multiple, separate expressions in a function definition makes sense when you're creating side effects--e.g. adding print statements for debugging.)

Defining my own max function with variable arguments

I'm learning Clojure solving the problems listed on 4clojure. One of the exercises is to create your own max function with variable arguments.
I'm trying to solve this easy problem using the REPL and I got to this solution:
(defn my-max
[first & more] (calc-max first more))
(defn calc-max
[m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else calc-max m (rest x)))
Which works fine but the exercise doesn't allow the use of def and therefore I must crunch both functions into one. When I replace the calc-max reference with its code the result is:
(defn my-max
[first & more]
((fn calc-max
[m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else calc-max m (rest x)))
first more))
But this code doesn't work and returns the next error:
user=> (my-max 12 3 4 5 612 3)
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
I guess this error comes from trying to evaluate the result of the calc-max function and I guess it's a syntax error on my part, but I can't figure out how to resolve it.
Here is the function I used to solve it. The point is not to use max at all.
(fn [& args] (reduce (fn [x y] (if (> x y) x y) ) args ) )
Real error is that you called parameter first - it rebinds real first function to number! Just change name to something other, and your variant will work. Although it maybe better explicitly name function, instead of calling anonymous function, for example, you can declare calc-max as local function using letfn, for example. So your my-max will look like:
(defn my-max [ff & more]
(letfn [(calc-max [m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x)
(rest x))
:else (calc-max m (rest x))))]
(calc-max ff more)))
Although, I think, that you can write simpler code:
(defn my-max [& more] (reduce max more))
Your function doesn't work because first in fn treated as function and not as input value. So when you write
user=> (my-max 12 3 4 5 612 3)
it's talling that can't cast 12 to function. Simply, it can be rewrited as
(defn my-max1 [fst & more]
((fn calc-max [m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else (calc-max m (rest x))))
fst more))
or even without fn
(defn my-max [x & xs]
(cond (empty? xs) x
(> (first xs) x) (recur (first xs) (rest xs))
:else (recur x (rest xs))))
To elaborate a little more on the exception that you are seeing: whenever Clojure throws something like
java.lang.Integer cannot be cast to clojure.lang.IFn
at you it means that it tried to call a function but the thing it tried to call was not a function but something else. This usually occurs when you have code like this
(smbl 1 2 3)
If smbl refers to a function, clojure will execute it with parameters 1 2 and 3. But if smbl doesn't refer to a function then you will see an error like the one above. This was my pointer in looking through your code and, as 4e6 pointed out, (first x) is the culprit here because you named your function argument first.
Not as good as the reduce but ok ba:
(fn [& args]
(loop [l args, maxno (first args)]
(if (empty? l)
maxno
(if (> maxno (first l) )
(recur (rest l) maxno)
(recur (rest l) (first l))))))
Can use cond I suppose

print list of symbols in clojure

I was trying to print out a list of symbols and I was wondering if I
could remove the quotes.
(def process-print-list
(fn [a-list]
(cond (empty? a-list) 'false
(list? a-list) (let [a a-list] (println (first a)) (process-print-
list (rest a) ))
:else (process-print-list (rest a-list) ))))
the list is ('x 'y 'z))
with the following output:
(quote x)
(quote y)
(quote z)
I am Just trying to get it to print out:
x
y
z
('x 'y 'z) is a syntactic abbreviation for ((quote x) (quote y) (quote z)). If you actually want a list of symbols (i.e. (x y z)), you're probably quoting too much somewhere.
'(x y z) ;=> (x y z)
'('x 'y 'z) ;=> ((quote x) (quote y) (quote z))
(list 'x 'y 'z) ;=> (x y z)
Generally, do not construct lists using quotation unless you know what you're doing. Use the list constructor instead.
On another note, I'd choose iteration over recursion here. This works fine:
(doseq [sym some-list]
(println sym))
You should use name fn to get symbol name.
(def my-list (list 'x 'y 'z))
(defn process-list
[a-list]
(map #(name %) a-list))
(process-list my-list)
;=> ("x" "y" "z")
Or with printing
(defn process-print-list
[a-list]
(doall (map #(println (name %)) a-list))
nil)
(process-print-list my-list)
;x
;y
;z
;=>nil
Or combine those to get return type you want...