3

When I want to know whether a list includes a value, I can use member function.

(member "a" '("a" "ā" "á" "ǎ" "à"))

Is there similar way to check if a vector includes a value?

(member "a" ["a" "ā" "á" "ǎ" "à"])
;=> nil
phils
  • 48,657
  • 3
  • 76
  • 115
ironsand
  • 403
  • 3
  • 14

3 Answers3

4

You can use cl-position, from the cl-seq package:

ELISP> (cl-position "a" ["a" "ā" "á" "ǎ" "à"] :test #'equal)
0 (#o0, #x0, ?\C-@)
ELISP> (cl-position "b" ["a" "ā" "á" "ǎ" "à"] :test #'equal)
nil

If it returns an integer, your vector contains the element. If it returns nil, the vector does not.

You have to use a test function that can compare strings; the default test won't treat two strings containing the same characters as equivalent; you can use #'test, as above, to do this.

Unfortunately, cl-member also requires a list, but cl-position definitely works, with the caveat that it returns the index the element is at, and not t.

zck
  • 8,984
  • 2
  • 31
  • 65
  • Thanks! I find it weird though that `member` is implemented in C, wheras `cl-position` is in ELisp. That should slow down the operation, I wonder if there's some other, actually native way… – Hi-Angel Mar 31 '23 at 11:36
3

You can always convert the vector to a list, and then test with member:

(member "a" (append ["a" "ā" "á" "ǎ" "à"] ()))

Because this is the normal list function member, if the value is a member the return value is the "tail" of the vector, as the sublist whose car is that value.

For example, (member "á" (append ["a" "ā" "á" "ǎ" "à"] ())) returns ("á" "ǎ" "à"). In some contexts, this can be an advantage.

Also the built-in function append is quite fast in this context. However, this does create a list, which means there is a cost for consing.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • This defeats the purpose of vector. You want a vector over a list because of cache locality *(I ignore other differences as in the context of searching a member mostly this one matters)*, but your answer suggests to convert it back to the list which degrades the performance. Not to mention the time taken for conversion. It should be mentioned that this is just a hack, not an actual solution. – Hi-Angel Mar 31 '23 at 11:29
  • @Hi-Angel: This a correct answer to the question as posed. This does **not** *convert* anything - the original vector remains unchanged. Yes, if performance is critical in some context then you might want to search for another solution that tests the vector directly (depends on the context, size of the vector,...). – Drew Mar 31 '23 at 19:01
1

There are also options in the in-built seq.el library:

(require 'seq)
(seq-position ["a" "ā" "á" "ǎ" "à"] "a")
=> 0

(seq-contains ["a" "ā" "á" "ǎ" "à"] "a")
=> "a"
phils
  • 48,657
  • 3
  • 76
  • 115