迭代字符串

问题描述 投票:0回答:5

我有两个长度相同的字符串,它们只有一个字符不同,我想要一个所有字符都相等的字符串。所以基本上是这样的,它的计算结果是一个字符串而不是字符列表:

(loop for a across "abcd"
      for b across "abce"
      when (char= a b) collect a)

虽然性能在这里不是问题,但我发现周围有

(coerce ... 'string)
很麻烦。

所以我想出了类似的东西

(loop with result = ""
      for a across "abcd"
      for b across "abce"
      when (char= a b)
        do (setf result (concatenate 'string result (string a)))
      finally (return result))

它可以完成工作,但对我来说看起来不太优雅。

(map 'string (lambda (a b) (when (char= a b) a)) "abcd" "abce")

看起来更好,但不起作用,因为当

NIL
a
不相等时,
b
不是一个字符。

是否有更优雅的习惯用法来迭代字符串并返回字符串?

string loops iteration common-lisp
5个回答
6
投票
(loop with result = ""
      for a across "abcd"
      for b across "abce"
      when (char= a b)
        do (setf result (concatenate 'string result (string a)))
      finally (return result))

对于较长的字符串,重复连接并不是一个好主意。

替代方案:

循环进入列表并强制转换为字符串

CL-USER 3 > (loop for a across "abcd"
                  and b across "abce"
                  when (char= a b) collect a into list
                  finally (return (coerce list 'string)))
"abc"

使用流并将其转换为字符串

CL-USER 4 > (with-output-to-string (*standard-output*)
              (loop for a across "abcd"
                    and b across "abce"
                    when (char= a b) do (write-char a)))
"abc"

使用可调节弦

CL-USER 5 > (loop with string = (make-array 0
                                            :element-type 'character
                                            :adjustable t
                                            :fill-pointer 0)
                  for a across "abcd"
                  for b across "abce"
                  when (char= a b) do (vector-push-extend a string)
                  finally (return string))
"abc"

6
投票

另一种可能性是使用

mismatch
,如 David Hodge 的评论中所示:

CL-USER> (defun f(a b)
           (let ((pos (mismatch a b)))
             (concatenate 'string (subseq a 0 pos) (subseq a (1+ pos)))))
F
CL-USER> (f "abcdefg" "abcxefg")
"abcefg"

2
投票

使用

map
同时循环多个列表

(map 'string #'(lambda (a b) (if (char= a b) a #\Rubout)) "abce" "abcd")

'string
将结果列表强制转换为字符串。
#\Rubout
get 被强制转换为零长度字符串。
#\Backspace
甚至会删除最后一个字符。


0
投票

另一种方式(它不假设任何有关元素位置的信息)

    (defun only-matching (seq1 seq2)
      (remove-if-not (lambda (c) (find c seq1)) seq2))

    CL-USER> (only-matching "abcd" "abce")
    "abc"
    CL-USER> (only-matching "abdc" "abec")
    "abc"`

(coerce
 (intersection (coerce "abdc" 'list)
               (coerce "abec" 'list))
 'string)

这也不保持秩序

注意:remove-if-not 已“正式”弃用。


0
投票

ITERATE

loop
替换库允许您在其
collect
版本中指定类型来指定返回的内容,而不是默认列表:

CL-USER> (iter
           (for a in-string "abcd")
           (for b in-string "abce")
           (when (char= a b)
             (collect a result-type string)))
"abc"

另请注意,它有一个专门用于字符串的迭代形式 (

in-string
),尽管通用向量形式 (
in-vector
) 也可以工作。

© www.soinside.com 2019 - 2024. All rights reserved.