获取字符串中使用的字母列表的好方法或有效方法是什么

时间:2013-01-06 01:06:42

标签: string common-lisp

简单地说,如何从Common Lisp中的字符串中获取列表中不重复的字母?

e.g:

"common"
-> ("c" "o" "m" "n") or in characters, (#\c #\o #\m #\n)
I'd care less about the order and type, if it is in string or character.

"overflow" -> (o v e r f l w)
"tomtomtom" -> (t o m)
   etc...

我在想的是收集原始字符串的第一个字母, 然后使用该功能;

(remove letter string)

收集现在的第一个字母删除字母字符串并将其附加到之前已收集的字母中。 这听起来像递归,但如果递归调用会松开以前收集的* letter * s列表,对吗?我也怀疑是否有任何内置功能。<​​/ p>

此外,我不想使用 set 或其中任何一个,因为我想要 完全以功能的方式做到这一点。

感谢您的时间。

3 个答案:

答案 0 :(得分:8)

CL-USER> (remove-duplicates (coerce "common" 'list))
(#\c #\m #\o #\n)

或者你甚至可以这样做:

CL-USER> (remove-duplicates "common")
"comn"

答案 1 :(得分:0)

如果您可以对正在处理的文本做出一些假设,那么可能有更好的可能性。例如,如果您正在处理英文文本 only ,那么您可以实现一个非常简单的哈希函数(基本上,使用长度为128个元素的位向量),这样您甚至不需要使用哈希表(这是一个更复杂的结构)。下面的代码说明了这个想法。

(defun string-alphabet (input)
  (loop with cache =
       (coerce (make-array 128
                           :element-type 'bit
                           :initial-element 0) 'bit-vector)
     with result = (list input)
     with head = result
     for char across input
     for code = (char-code char) do
       (when (= (aref cache code) 0)
         (setf (aref cache code) 1
               (cdr head) (list char)
               head (cdr head)))
     finally (return (cdr result))))

(string-alphabet "overflow")
;; (#\o #\v #\e #\r #\f #\l #\w)

强制转换到bit-vector并不是很重要,但它更容易调试(打印的表单更紧凑),并且某些实现可能实际上优化它以仅包含平台需要表示的那么多整数在64位平台上,很多位,即在128位长度的情况下,它可能短至2或3个整数长。

或者,你也可以这样做,使用整数:

(defun string-alphabet (input)
  (loop with cache = (ash 1 128)
     with result = (list input)
     with head = result
     for char across input
     for code = (char-code char) do
       (unless (logbitp code cache)
         (setf cache (logior cache (ash 1 code))
               (cdr head) (list char)
               head (cdr head)))
     finally (return (cdr result))))

但在这种情况下,在最糟糕的情况下,你会创建128个大整数,毕竟这并不是那么昂贵,但位向量可能会做得更好。但是,这可能会为您提供一个提示,当您可以假设,例如,只使用英文字母的字母时(在这种情况下,可以使用比机器内存字短的整数)。

答案 2 :(得分:-5)

这里有一些Haskell中的代码,因为我对Lisp不是很熟悉,但是因为它们都是功能性的,我不认为,翻译它会有问题:

doit :: String -> String

doit [] = []
doit (x:xs) = [x] ++ doit (filter (\y -> x /= y) xs)

那是什么呢?你有一个String,如果它是一个空字符串(在Haskell [] ==“”中),你返回一个empty字符串。 否则,取第一个element并将其连接到字符串的tail上的递归,但filter除去那些== first element的元素。

此函数filter只是特定map-function的语法糖,在Lisp中称为remove-if,您可以在此处重读:lisp filter out results from list not matching predicate