您好我正在尝试编写一个程序,其中给定一个列表列表,检查它们是否大小相等,如果它们返回#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的长度设置为第一个列表的长度之后。任何帮助将不胜感激。
答案 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-lengths
和all-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。