6

According to documentation, member checks if a a given element is an element of a list. For example if the list, say my_list consists of apple and orange, (member "apple" my_list) returns true.

Is there an easy way to check if a given string is a part of a string of a list. For example ap is a part of a string of the above list. Hence it would be desirable to have a function like my-function such that (my-function "ap" my_list) returns true.

Drew
  • 75,699
  • 9
  • 109
  • 225
Name
  • 7,689
  • 4
  • 38
  • 84

4 Answers4

6

The easiest way is to use the Common Lisp compatibility layer:

(require 'cl-seq)
(cl-member "ap" '("foo" "apa" "bar") :test #'string-match)
==> ("apa" "bar")

PS. This is not directly relevant to your question, but if you have a few minutes to kill, keep reading. ;-)

Note that Emacs maintainers have traditionally eschewed CL (starting with the original political animosity of RMS towards the CL creators).

See Controversy of Common Lisp Package in Emacs Lisp for attempts to justify the hostility in technical terms.

sds
  • 5,928
  • 20
  • 39
5

The function that comes to my mind at least would be cl-member using a string-match-p test.

Here's a short example that shows how to use it:

ELISP> (setq testing '("an apple" "a pear" "a grape"))
("an apple" "a pear" "a grape")

ELISP> (cl-member "apple" testing)
nil
ELISP> (cl-member "an apple" testing)
nil
ELISP> (cl-member "an apple" testing :test #'string=)
("an apple" "a pear" "a grape")

ELISP> (cl-member "a pear" testing :test #'string=)
("a pear" "a grape")

ELISP> (cl-member "a pear" testing :test #'string-match-p)
("a pear" "a grape")

ELISP> (cl-member "pear" testing :test #'string-match-p)
("a pear" "a grape")

ELISP> (cl-member "xx" testing :test #'string-match-p)
nil

Note that member and cl-member doesn't actually return true but the sublist that contains the sought element. That in turn will eventually evaluates to true in tests, but That's mostly a minor detail.

Edit:

Sean pointed out an important detail about string-match and string-match-p: Regular expression meta-characters in the search string might give an erroneous result. If that's a problem you could examine the raw sequence instead with cl-search:

ELISP> (setq test (list "apple" "pear" "grape"))
("apple" "pear" "grape")

ELISP> (cl-member "ap" test :test #'cl-search)
("apple" "pear" "grape")

ELISP> (cl-member "gra" test :test #'cl-search)
("grape")
Xaldew
  • 1,181
  • 9
  • 20
1

A solution that almost doesn't require cl-lib (only cl-defgeneric and cl-defmethod):

(seq-some (lambda (x) (string-match "foo" x)) '("f" "fo" "fooo"))

And a solution that doesn't require cl-lib

(defun some-string-matches (search strings)
  (while (and strings (not (string-match search (car strings))))
    (setq strings (cdr strings)))
  strings)

Just so it would live up to the title.

wvxvw
  • 11,222
  • 2
  • 30
  • 55
0

Use mapcar, you can test anything in a lambda.

This example here will return multiple headings that start with "someday.org/Personal/Foo..." which is not what I want.

;; Wrong dont use
(cl-member "someday.org/Personal" (org-refile-get-targets) :test 'string= :key 'car )

Instead use mapcar which only returns the correct one.

;; Correct
(delq nil
(mapcar
  (lambda (x) (when (string= (car x) "someday.org/Personal") x)) (org-refile-get-targets)))
Rick
  • 25
  • 4