Search code examples
clojure

Clojure - find largest of list without using max


i'm trying to write a simple Clojure program to find the maximum element of a list. This is the code I wrote so far:

(ns iotest.core
  (:gen-class))

(defn getLargest [L]
  "Get the largest element of a given list L"
  (cond
   (empty? L) nil
   (empty? (rest L)) (first L)
    ((> (first L) (getLargest (rest L)))) (first L)
    :else (getLargest (rest L))))

(defn -main []
  (let
    [L (4 5 10 1)
     largest (getLargest L)]
    (println "Largest element of" L "is" largest)))

The problem is, I get the following error(i'm using leiningen):

class java.lang.Long cannot be cast to class clojure.lang.IFn (java.lang.Long is in module java.base of loader 'bootstrap'; 
clojure.lang.IFn is in unnamed module of loader 'app')

What I'm doing wrong?

I know about the max function, but I want to implement it by myself for learning purposes.


Solution

  • This part:

     (let [L (4 5 10 1) ... )
    

    is missing quote- or you can use vector instead:

    (4 5 10 1)
    error
    
    '(4 5 10 1)
    => (4 5 10 1)
    
    [4 5 10 1]
    => [4 5 10 1]
    

    There is also error with ((> (first L) (getLargest (rest L)))) (first L) (class java.lang.Boolean cannot be cast to class clojure.lang.IFn, you have additional pair of parentheses here) and style error with getLargest- Clojure uses kebab-case, so correct name is get-largest.

    For correct result check reduce. Min and max don't work for empty lists, so you have to be careful about that:

    (defn get-largest [lst]
      (if (empty? lst) 
        :none
        (reduce (fn [acc element] 
                  (if (> element acc) element acc))
                (first lst)
                (rest lst))))
    
    (let [lst [4 5 10 1]
          largest (get-largest lst)]
      (println "Largest element of" lst "is" largest))
    
    Largest element of [4 5 10 1] is 10
    => nil
    
    (let [lst []
          largest (get-largest lst)]
      (println "Largest element of" lst "is" largest))
    
    Largest element of [] is :none
    => nil
    

    EDIT: This is a little bit better:

    (defn get-largest [lst]
      (when (seq lst)
        (reduce #(if (> %2 %1) %2 %1)
                (first lst)
                (rest lst))))
    
    (let [lst [4 5 10 1]]
      (if-let [largest (get-largest lst)]
        (println "Largest element of" lst "is" largest)
        (println "Sequence is empty")))
    
    Largest element of [4 5 10 1] is 10
    => nil