计划中的列表长度

时间:2012-03-22 00:16:12

标签: scheme

您好我正在尝试编写一个程序,其中给定一个列表列表,检查它们是否大小相等,如果它们返回#t。

那么例如,如果我要写(列表计数器?'((1 2 3)(4 5 6)(7 8 9)))程序将返回#t,和(列表计数器?'( (1 2 3)(4 5 6)(7 8)))将返回#f。

到目前为止,这就是我所做的:

 (define list-counter?
  (lambda (x)
    (if (list? x)
        (if (list?(car x))
      (let (l (length (car x))))
        (if (equal? l (length(car x))))
        (list-counter?(cdr x))
 ) ) ) ) ) 

我认为我错误的地方是在我将l的长度设置为第一个列表的长度之后。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:4)

有几种方法可以解决这个问题。例如,手动并逐步进行:

(define (all-lengths lists)
  (if (null? lists)
      '()
      (cons (length (car lists))
            (all-lengths (cdr lists)))))

(define (all-equal? head lengths)
  (if (null? lengths)
      true
      (and (= head (car lengths))
           (all-equal? head (cdr lengths)))))

(define (list-counter? lists)
  (let ((lengths (all-lengths lists)))
    (all-equal? (car lengths) (cdr lengths))))

让我解释一下上述程序。我将问题分为两步,首先创建一个包含每个子列表长度的新列表 - 这就是all-lengths的作用。然后,将列表中的第一个元素与其余元素进行比较,看看它们是否完全相同 - 这就是all-equal?的作用。最后,list-counter?将所有内容组合在一起,使用正确的参数调用前面的两个过程。

甚至更简单(也更短),使用列表程序(高阶程序):

(define (list-counter? lists)
  (apply = (map length lists)))

为了理解第二种解决方案,请注意all-lengthsall-equal?代表更一般程序的特殊情况。当我们需要创建一个新列表,其结果是将过程应用于另一个列表的每个元素时,我们使用map。当我们需要将一个过程(在这种情况下为=)同时应用于列表的所有元素时,我们使用apply。而这正是list-counter?的第二个版本正在做的事情。

答案 1 :(得分:1)

您可以像这样编写all-equal?函数:

(define (all-equal? list)
  ;; (all-equal? '()) -> #t
  ;; (all-equal? '(35)) -> #t
  ;; (all-equal? '(2 3 2)) -> #f
  (if (or (null? list) (null? (cdr list)))
      #t
      (reduce equal? list)
  ))

然后做:

(all-equal? (map length listOfLists))

或者你可以这样做:

(define (lists-same-size? list-of-lists)
    (if (== (length listOfLists) 0)
      #t
      (let*
        (( firstLength
             (length (car listOfLists)) )
         ( length-equal-to-first?
             (lambda (x) (== (length x) firstLength)) )
        )
        (reduce and #t (map length-equal-to-first? listOfLists))
      )
    )))

这说的是:如果列表长度为0,我们的语句是空的,否则我们捕获列表长度的第一个元素(在if - 子句的'else'部分),put它在由let的句法糖(实际上是一个lambda)定义的闭包中,并用它来定义length-equal-to-first?函数。

不幸的是reduce并不懒惰。如果我们发现只有一个不相等,我们真正喜欢的是避免计算列表的长度。因此,为了提高效率,我们可以做到:

    ...
       (let*
         ...   
         ( all-match?               ;; lazy
             (lambda (pred list)
               (if (null? list) 
                   #t 
                   (and (pred (first list)) (all-match? (cdr list)))
                      ;;^^^^^^^^^^^^^^^^^^^ stops recursion if this is false
             )) )
        )
        (all-match? length-equal-to-first? listOfLists)
      )
    )))

请注意,all-match?已经通过麻省理工学院计划的(list-search-positive list pred)(for-all? list pred)有效定义,或者作为andmap在Racket中定义。


为什么写这么长时间?

你被迫写一个基础案例,因为你的减少没有规范元素,因为它依赖于第一个元素,而大多数语言中的列表操作并不是很强大。在Python等其他语言中你甚至会遇到同样的问题。如果这有帮助:

第二种方法:

if len(listOfLists)==0:
    return True
else:
    firstLength = len(listOfLists[0])
    return all(len(x)==firstLength for x in listOfLists)

然而,使用任何语言编写第一种方法都要简单得多,因为它忽略了基本情况而忽略了这个问题。

第一种方法:

if len(listOfLists)<2:
    return True
else:
    return reduce(lambda a,b: a==b, listOfLists)

答案 2 :(得分:0)

这可能听起来有点奇怪,但我认为这很容易。

运行列表,构建一个包含每个(包含)列表长度的新列表,即地图长度。
运行构造的长度列表,将头部与其余部分进行比较,如果它们与头部完全相同则返回#t。一旦它与头部不匹配就返回false。