基于Lisp中的字符匹配对列表进行排序

时间:2016-02-16 05:52:38

标签: lisp common-lisp

根据拼写中的常用字符计算并返回候选列表。

例如, 如果列表是:( TEAM TEEN,然后那个时间段) 你在函数中提供参数(“thim”) 那么它应该按照列表中常见字符的相似性对列表进行排序。 它应该返回:(那个时间团队,然后是镇上的) 由于THEM具有更常见的“thim”特征所以它首先出现等等。

我的尝试:

       (defun correctSX_SIM(word)

        (setf w (correctSX word))  ; w is list of words.
        (sort w #'eq :key #'car)

       )

我知道我的答案已经过时了。但我需要LISP的帮助,因为我不了解LISP的所有功能。

2 个答案:

答案 0 :(得分:5)

首先,为已知单词列表定义一个特殊变量:

(defparameter *dictionary* '(TEAM TEEN THAN THEM THEN TIME TOWN))

您必须为符合要求的字词定义距离功能。如果我没有记错,以下情况应该有效:

(defun distance (u v)
  (- (length (intersection (coerce u 'list)
                           (coerce v 'list)))))

我们查看两个字符串中共同的元素数量并将其否定,以便共享最大元素数量的元素具有最低分数。我不知道它是否重要,但长相同的字符串得分低于短的相同字符串。

根据您的要求,您需要执行稳定的排序,以便与所选单词保持相同距离的单词保持其相对顺序。这也是我使用严格#'<比较函数的原因:当比较与输入具有相等距离的两个单词 a b 时,比较返回{{1两个 a&lt; b b&lt; ,允许STABLE-SORT知道 a b 等同于w.r.t.偏序。 另请注意,我使用COPY-LIST来避免改变字典。对于您的示例,实际排序如下:

nil

结果与您的示例略有不同,但我认为它符合your comment THAN 应该在 THEN 之前,因为(i)在此如果距离相同,则(ii)它们在原始列表中以该顺序出现。

如@jkiiski的评论中所述,对于每次比较,可以调用一次距离函数(即 O(n.log(n)))。在我看来,在这种特殊情况下,距离函数非常便宜,但是如果数据集较大且距离更复杂,那么缓存中间结果肯定会有所回报。您至少有两个选择:

  • 定义另一个缓存已知结果的距离函数(memoization)。这种方法的优点是您可以在排序部分和距离函数之间保持严格的分离。这应该足够了:

    (stable-sort (copy-list *dictionary*) 
                 #'< 
                 :key (lambda (e) (distance "THIM" (string e))))
    
    => (them time team than then teen town)
    
  • 预先计算到包含(ql:quickload :memoize) (org.tfeb.hax.memoize:memoize-function 'distance :key #'identity :test #'equal) 对的另一个列表的距离,并根据第一个元素进行排序。然后,提取所有第二个元素以具有一系列字符串。显然这被称为Schwartzian transform(感谢Svante)。这里整个过程更加明确:

    (distance string)

但是有一个主要区别:使用 memoized 版本,您可以在排序的不同调用中保持已知结果(除非您明确地清除它们),而使用 sorted-dictionary < / em>,一旦计算出结果列表,就丢弃中间距离。

答案 1 :(得分:1)

有一种Levenshtein distance算法可用于衡量两个单词之间的差异。 Here您可以找到Common Lisp的完整实现。此外,显示两个字符串之间差异的更简单方法是set-difference函数,如here所示。