【问题标题】:Common-Lisp: How to sort the characters of a string?Common-Lisp:如何对字符串的字符进行排序?
【发布时间】:2025-12-17 13:40:01
【问题描述】:

我知道如何用我知道的所有其他语言做到这一点,但我刚刚开始使用 Lisp,还没有完全掌握它。我的想法

  • 制作一个字符列表
  • 转换为 ascii 值
  • 排序
  • 转回字符
  • 转回字符串

看起来很笨拙。有没有更好的方法来做到这一点?我正在尝试编写一个函数,给定一个字符串,返回一个按字母排序的字符串。所以,例如:

gate => aegt
house => ehosu
door => door

此例程将用作字谜查找器的一部分。

谢谢!

【问题讨论】:

    标签: common-lisp


    【解决方案1】:

    在 Common Lisp 中,字符串是序列,sort 适用于任何序列类型,所以它可以解决问题。

    这是一个例子:

    (let ((the-string (copy-seq "this is the string")))
      (sort the-string #'char-lessp))
    ;; => "   eghhiiinrsssttt"
    

    还有here'ssortstable-sort 的Hyperspec 条目。只需选择您的谓词(sort 的第二个参数)即可获得所需的排序顺序。

    请注意,我在示例中使用了 copy-seq,因为 sort 具有破坏性 - 它就地修改了字符串。

    【讨论】:

    • 很好的解释,谢谢。 #'char-lessp#'char< 更受欢迎,还是只是一种风格?
    • 谢谢 Olie,很高兴我能帮上忙。不同之处在于#'char-lessp 忽略大小写,而#'char< 不忽略。 (#'string-lessp#'string< 相比也是如此)。
    • 我认为复制一个文字字符串有点过分......你不可能通过改变它来影响其他任何东西,因为你只是在这里定义它。
    • @wvxvw 常量折叠...我认为(尽管我必须仔细阅读 CLHS 以确认)完全允许 ​​CL 实现将 (let ((a "foo") (b "foo")) ...) 折叠成 (let ((#:temp "foo)) (let ((a #:temp) (b #:temp)) ...)) 和在这种情况下,排序a 会作为一个令人惊讶的副作用排序b
    • @wvxvw,LispWorks 的文档明确将字符串(和一般的向量)标识为eligible for constant folding。在底部的示例中,他们建议不要在不使用 copy-seq 的情况下将定义为文字的变异向量。
    【解决方案2】:

    sort 函数接受一个序列,而该序列已经是一个字符串,因此您唯一的问题是找到正确的比较函数。字符不是数字,所以你应该使用字符比较函数,例如char>:

    * (sort (copy-seq "hello") #'char>)
    
    "ollhe"
    

    【讨论】:

    • 啊,谢谢!我知道字符串是序列,但不知道#'char>——完美!
    • 顺便说一句,您的回答是正确的,首先,但我选择了 jbm,因为 (a) 他提供了更多细节,这对我的情况很有帮助,并且 (b) 我想鼓励低代表给出了很好答案的海报(我认为他在我选择它的时候是 2xx。)所以:没什么私人的,你的回答也很棒!但是 SO 说“只能有一个”。 ;)
    【解决方案3】:

    字符串是一个字符序列。 sort 对序列进行排序,因此它对字符串进行排序就像对列表进行排序一样:

    (setq tester (copy-seq "lkjashd")) =>  "lkjashd"
    (stable-sort tester #'char-lessp) =>  "adhjkls"
    tester => "adhjkls" ; NB: it mutates the string!
    

    【讨论】: