views:

39

answers:

2

In this StackOverFlow question, I created an employee database and provided a select-by-first function. How can I write a select-by-first-pattern where the record is returned if any part of the string/symbol matches?

(select-by-first-pattern 'ev); Returns all records containing "ev" (eg. Steve)

Here's the code needed to construct the database: (UPDATED: Included suggested solution)

(require 'cl)
(defvar *emp-db* nil)
(defun add-record (emp) (push emp *emp-db*))

(defstruct employee age first-name last-name sex children)

(add-record (make-employee))

(add-record (make-employee :age 34
      :last-name 'farquharson
      :first-name 'alice
      :sex 'female))

(add-record (make-employee :age 43
      :last-name 'jobs
      :first-name 'steve
      :sex 'male))

(add-record (make-employee :age 53
      :last-name 'ballmer
      :first-name 'steve
      :sex 'male))

(defun select-by-first (first-name)
  (remove-if-not
   #'(lambda (employee)
       (equal (employee-first-name employee) first-name))
   *emp-db*))

;; ---------- Answer below ----------
;;
(defun select-by-first-pattern (first-name)
  (remove-if-not
   #'(lambda (employee)
       (if (string-match first-name (symbol-name (employee-first-name employee))) t nil))
   *emp-db*))

(print (select-by-first-pattern "al")); Returns alice's record
(print (select-by-first-pattern "ev")); Returns records of the two Steve's
(print (select-by-first-pattern "ee")); Returns nil
+1  A: 

If you want to do partial or pattern matches, you really should be using strings. I don't have any experience with Common Lisp proper, but Emacs has a wealth of regex-matching functions.

If you really are stuck with symbols as inputs, you could use symbol-name (in Elisp at least) to get the name of the symbol as a string. Either way, you're going to end up comparing strings, so you might as well use them to begin with.

haxney
symbol-name exists in Common Lisp but it returns the string in uppercase. Elisp has string-match and CL has a different library.
I added your suggestion to my question. Problem solved. Thanks.
Common Lisp symbols are case sensitive. If CL returns symbol names as uppercase, then because they are uppercase. The reader turns foo into the name "FOO" by default. If you want to use different cases, you need to write |Steve Jobs|, where the symbol name is the string "Steve Jobs".
Rainer Joswig
A: 

Use SYMBOL-NAME to convert a symbol to a string, by preserving the original case:

> (symbol-name '|Alice|)
"Alice"

For simple string searches, you can use the SEARCH function:

> (search "li" (symbol-name '|Alice|))
1
> (search "li" (symbol-name '|Dave|))
NIL

For complex pattern matching, probably this library can help.

Vijay Mathew