views:

111

answers:

3

I need to make a decision about a string based on the first character, and I have a method defined in this way:

(defn check-first [string]
  (case (get string 0)
    "+" 1
    "-" 2
    3
    ))

Currently it always returns 3 even when the string starts with those characters. What am I doing wrong? Also, is there a more elegant way to implement this?

A: 

Did you mean to use cond?

http://clojure-notes.rubylearning.org/

(def x 10)
(cond
(< x 0) (println "Negative!")
(= x 0) (println "Zero!"))
; => nil

(cond
(< x 0) (println "Negative!")
(= x 0) (println "Zero!")
:default (println "Positive!"))
; => Positive!
Nikki9696
+7  A: 
(get "foo" 0)
;; => \f

(get "foo" 0) returns a char, not a string, so, if you want to use your check-first, you'll need to replace the strings with characters.

(defn check-first [s]
  (case (first s) \+ 1, \- 2, 3))

By the way, Clojure Library Coding Standards recommend using s as the argument name for functions requiring string input.

If you would prefer to use strings in place of chars: (str (first "foo")) or (subs "foo" 0 1) => "f"

Alternatively, one could write a case-indexed macro.

The following is a quick hack, and provides no option for a default expression:

(defmacro case-indexed [expr & clauses]
  (list* 'case expr (interleave clauses (iterate inc 1))))

;; (case-indexed "foo" "bar" "baz" "foo") => 3
;; (case-indexed (+ 5 1) 3 4 5 6 7) => 4

(defn check-first [s]
  (case-indexed (first s)
    \+, \-, \*, \/))

I don't think I'd separate the clauses like this - it was just to keep the answer more concise.

I'd recommend extending case-indexed for default expressions if one were to use this, though. Also, check-first seems too general a name for this function; I've no better suggestions, but I'd think about changing it. (assuming it wasn't made-up for the purpose of this question.)

MayDaniel
+1  A: 

You can keep what you have and use Java's substring method in your case condition:

(defn check-first [s]
  (case (.substring s 0 1)
    "+" 1
    "-" 2
    3))

Edit: Just noticed that MayDaniel had already mentioned subs, which works the same way as .substring. Sorry, it's early here...

Michael Kohl