anon
anon

Reputation:

How can I perform a partial symbol match on a defstruct?

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

Upvotes: 2

Views: 239

Answers (2)

Vijay Mathew
Vijay Mathew

Reputation: 27174

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.

Upvotes: 1

haxney
haxney

Reputation: 3438

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.

Upvotes: 1

Related Questions