【问题标题】:collecting multiple maximum values收集多个最大值
【发布时间】:2013-10-14 04:04:30
【问题描述】:

我有一个元素列表。每个元素的结构如下:

('symbol "string" int-score)

示例列表:

(list (list 'object1 "wabadu" 0.5)
      (list 'object2 "xezulu" 0.6)
      (list 'object1 "yebasi" 0.5)
      (list 'object1 "tesora" 0.2))

我想检索特定符号的最大值。当我用符号object2 搜索时,我应该会返回:

('object2 "xezulu" 0.6)

如果我用object1 搜索,我应该会返回:

(('object1 "wabadu" 0.5) ('object1 "yebasi" 0.5))

我想收集特定对象的所有最高元素。我能做的是:假设上面的列表是下面使用的列表,并且我正在搜索object1。我可以检索特定对象的所有元素:

(loop for element in list
     when (equal 'object1 (first element))
     collect element)

我还可以检索列表的最高元素:

(loop for element in list
     when (equal 'object1 (first element))
     maximize (third element))

但是,这只会返回一个元素。我想要的是 all 最大元素。我尝试了一些与collectmaximize 的组合,但我对语法的了解很少。有没有办法在“简单”函数中收集所有最高元素?

【问题讨论】:

  • 嗯...iterate 的第一个示例似乎是为了做您想做的事情...不过,我尝试了一下,但未能迭代以实际工作我,所以...暂时不将此视为答案。如果我弄明白了,我会发布一个;鼓励其他人打败我。

标签: loops lisp max common-lisp


【解决方案1】:

基于 LOOP 的版本示意图:

(defun mymax (target list &aux result max)
  (loop for (item name value) in list
        when (eql item target)
        do (cond ((or (null result)
                      (> value max))
                  (setf result (list (list item name value))
                        max value))
                 ((= value max)
                  (push (list item name value) result))))
  result)

【讨论】:

    【解决方案2】:

    这将创建一个hash-table,其中键是符号,值以(maximum . (list of strings corresponding to maximum))的方式排列

    (let ((data (list (list 'object1 "wabadu" 0.5)
                      (list 'object2 "xezulu" 0.6)
                      (list 'object1 "yebasi" 0.5)
                      (list 'object1 "tesora" 0.2))))
      (loop
         :with table := (make-hash-table)
         :for (item string num) :in data :do
         (destructuring-bind (&optional max strings)
             (gethash item table)
           (cond
             ((or (null max) (< max num))
              (setf (gethash item table) (list num (list string))))
             ((= max num)
              (setf (cdr strings) (cons string (cdr strings))))))
         :finally (return table)))
    
    ;; #<HASH-TABLE {1005C6BE93}>
    ;; --------------------
    ;; Count: 2
    ;; Size: 16
    ;; Test: EQL
    ;; Rehash size: 1.5
    ;; Rehash threshold: 1.0
    ;; [clear hashtable]
    ;; Contents: 
    ;; OBJECT1 = (0.5 ("wabadu" "yebasi")) [remove entry]
    ;; OBJECT2 = (0.6 ("xezulu")) [remove entry]
    

    我认为使用此哈希表之后您的生活会比使用您当前拥有的数据结构更轻松。

    【讨论】:

      【解决方案3】:

      您可以通过 loop 遍历列表一次以选择具有正确第一个元素的所有子列表并确定最大值(您可以使用 intoloop 累积多个值),然后finally 子句中的第二个 loop 进行选择,现在只选择得分最高的那些:

      (loop for triple in *l*
            for (key nil score) = triple
            when (eq key 'object1)
              collect triple into selection
              and maximize score into max-score
            finally (return (loop for triple in selection
                                  when (eql (third triple) max-score)
                                    collect triple)))
      

      编辑:或者,这里可以非常简洁地使用delete 函数,而不是第二个循环:

      (loop for triple in *l*
            for (key name score) = triple
            when (eq key 'object1)
              collect triple into selection
              and maximize score into max-score
            finally (return (delete max-score selection
                                    :test #'/=
                                    :key #'third)))
      

      【讨论】:

      • 最后我选择了你的解决方案,我发现它是一个不错的选择。
      【解决方案4】:

      maximize 只返回一个元素。您可以按第三个组件对所有列表进行排序,然后获取最前面的。像这样:

      ;;; suppose a copy of the data is stored in l
      
      ;; get all 'object1 and sort them
      (setf l (sort (remove-if-not
                      (lambda (x) (equal (first x) 'object1)) l)
                    #'> :key #'third))
      ;; remove the ones with smaller value than the first one
      (setf l (remove-if
                (lambda (x) (< (third x) (third (first l)))) l))
      

      【讨论】:

        【解决方案5】:

        抽象您的数据以创建基本构建块;将构建块组合到您需要的功能中:

        (defun make-foo (type name score)
           (list type name score))
        
        (defun foo-type (foo) (elt foo 0))
        ;; ...
        
        (defun make-foos (&rest foos)
          foos)
        
        (defun foos-find-if (foos predicate)
          ;; return all foos satisfying predicate
          )
        
        (defun foos-maximize (foos orderer)
          ;; return the maximum foo (any one)
          )
        
        (defun foos-find-if-maximized (foos)
          (foos-find-if foos 
            (let ((max (foos-maximize foos #'foo-score)))
              (lambda (foo)
                (= (foo-score max) (foo-score foo))))))
        

        【讨论】:

          【解决方案6】:

          这是一种方法,首先保存symbol-list,它只包含带有搜索对象的列表。然后我们可以很容易地得到最大值,然后删除那些值较小的列表。

          (defun foo (symbol list)
            (let* ((symbol-list (remove-if-not #'(lambda (l) (eq (first l) symbol))
                                 list))
                   (max (apply #'max (mapcar #'third symbol-list))))
              (remove-if-not #'(lambda (l) (= (third l) max))
               symbol-list)))
          

          我们可以称之为:(foo 'object1 l)

          【讨论】:

            【解决方案7】:

            根据经验,如果您真的想将一系列事物归结为一个结果,那么使用 reduce 应该有一个很好的方法。

            还有:

            (defun collect-maxima-by-third (list)
              (reduce
               #'(lambda (max-list next-element)
                   (let ((max-value (third (first max-list)))
                         (next-value (third next-element)))
                     (cond ((< max-value next-value)
                            (list next-element))
                            ((= max-value next-value)
                             (cons next-element max-list))
                            (t max-list)))) ; the greater-than case
               (rest list)
               :initial-value (list (first list))))
            

            这并不完美,就像你给它一个空列表一样,它会给你一个包含一个空列表而不是一个空列表的列表,但是如果你认为这会经常发生,你可以很容易地为此添加一个案例。

            这种技术(可能不是这个确切的例子)在函数式编程的各种文本中都有详细说明;一些 Haskell 文本做得特别好(Learn You a Haskell 浮现在脑海中)。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-06-30
              • 2018-10-14
              • 1970-01-01
              • 2011-04-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多