如何找到多级列表的长度?

时间:2016-12-01 16:02:22

标签: list lisp common-lisp

( setq list1 '( a ( b ( c d ) e ) f ( g h ) i ) )
( print ( length ( list1 ) ) )

此处的输出为5,但我希望输出为9.如何打破列表并查找整个长度?

4 个答案:

答案 0 :(得分:3)

似乎你不想计算给定列表的长度,但是要计算原子的数量(树中的叶子)。 要做到这一点,您需要定义一个函数来检查参数是原子还是列表。在第一种情况下,它将返回1(原子中的原子数)。在第二种情况下,它将返回列表中每个单独分支的原子总和,使用相同的函数计算。 这应该足以让你开始。

答案 1 :(得分:2)

您想要计算(flatten list)的长度,其中flatten是一个可以轻松实现(或在Stackoverflow上找到)的函数。如另一个答案所述,您也可以直接编写一个计算总和的函数。另一种方法是使用SERIES包:

(defpackage :so (:use :cl :series))
(in-package :so)

(defun whole-length (tree)
  (collect-length (scan-lists-of-lists-fringe tree)))

测试

SO> (whole-length '( a ( b ( c d ) e ) f ( g h ) i ))
9

Macroexpanded code

Series包可以从高级功能代码生成有效的迭代循环。这里scan-lists-of-lists-fringe使用自己的堆栈在树中生成叶子流。 collect-length函数计算正在生成的元素。 以下是(collect-length ...)的宏观扩展。

(LET* ((#:OUT-1035 TREE))
  (LET (#:LEAVES-1032 (#:STATE-1034 (LIST (LIST #:OUT-1035))) (#:NUMBER-1029 0))
    (DECLARE (TYPE LIST #:STATE-1034)
             (TYPE FIXNUM #:NUMBER-1029))
    (TAGBODY
     #:LL-1036
      (IF (NULL #:STATE-1034)
          (GO SERIES::END))
      (SETQ #:LEAVES-1032 (CAR #:STATE-1034))
      (SETQ #:STATE-1034 (CDR #:STATE-1034))
      (SETQ #:LEAVES-1032 (CAR #:LEAVES-1032))
      (WHEN (NOT (ATOM #:LEAVES-1032))
        (DO ((SERIES::NS #:LEAVES-1032 (CDR SERIES::NS))
             (SERIES::R NIL (CONS SERIES::NS SERIES::R)))
            ((NOT (CONSP SERIES::NS))
             (SETQ #:STATE-1034 (NRECONC SERIES::R #:STATE-1034))))
        (GO #:LL-1036))
      (INCF #:NUMBER-1029)
      (GO #:LL-1036)
     SERIES::END)
    #:NUMBER-1029))

答案 2 :(得分:1)

您正在寻找的是一种计算表示为嵌套列表的树中的叶子的方法。这是一种快速,简单,实用的方法:

(defun count-leafs (tree)
  "Counts the number of leafs in a tree represented as nested lists"
  (cond ((null tree) 0)
        ((atom tree) 1)
        (t (+ (count-leafs (car tree))
              (count-leafs (cdr tree))))))

此函数将遍历树的所有节点并将所有"非列表"节点。如果某个节点不是列表,那么它必须是一个原子(叶子)。

(count-leafs '(1 2 3)) ; => 3
(count-leafs '(1 (22) 3)) ; => 3
(count-leafs '(1 (2 3 4 5 2) 3)) ; => 7
(count-leafs '(1 (2 3 ((4)) 5 2) 3)) ; => 7

答案 3 :(得分:0)

这对我有用,谢谢大家。 :)

( setq list1 '( a ( b ( c d ) e ) f ( g h ) i ) )
( print ( length list1 ) )
( defun flatten ( list1 )
  ( if ( atom list1 )
      ( list list1 )
      ( loop for a in list1
            appending ( flatten a )
             )
       )
    )
( print ( length ( flatten list1 ) ) )