Useful list function

Started by JeremyDunn, April 08, 2010, 08:01:58 PM

Previous topic - Next topic

JeremyDunn

As we all know ideas build up over time and turn into things we didn't initially imagine. In my case I started with a basic function that I used that was simple and useful and it has recently grown into something more useful. First, the code:



(define (length? lst (n 1)(op =) booltest)
  (and (op (length lst)
           (if (or (string? n)(list? n))(length n) n))
       (if booltest
           (if (list? booltest)
               (for-all true?
                  (map for-all booltest (dup lst (length booltest))))
               (for-all booltest lst))
           true
       )))


We often want to see if a list's number of arguments fits within a certain range and whether all of its members satisfy some criteria. Now we can test for both with the length? function. The length? function takes a list as argument and optionally can include an integer to test the length against, a comparison operator and a boolean test function to do a for-all comparison on the list. If all conditions are satisfied then true is returned. The test defaults to 1 and the comparison operator defaults to =. Here are some examples of how this works:



(length? lst) - does the list have 1 element?

(length? lst 2) - does the list have 2 elements?

(length? lst 3 >) - does the list have more than 3 elements?

(length? lst 3 = integer?) - do we have a list of 3 integers?

(length? lst 3 = (list integer? zero?)) - do we have a list of 3 integers that are 0?



That is pretty neat but there is more! If we have another list instead of a comparison number we can use a comparison operator to see how the number of arguments compare with one another. In this case we can only use <, = and > as comparators. Here are some more examples of how this works:



(length? lst1 lst2) - are the lists of equal length?

(length? lst1 lst2 >) - does lst1 have more arguments than lst2?

(length? lst1 lst2 <) - does lst1 have fewer arguments than lst2?



Of course one can compare string lengths this way as well. I think it is clear that this makes life much easier. Here is an example of how one could use the function in a practical way. The integer-vector? function determines if its input is a non-zero length list of integers.



(define (integer-vector? v)(length? v 0 > integer?))


So let the votes begin, should this be a new function in the language? Can it be generalized even more?

JeremyDunn

#1
Here is yet another enhancement I have recently added. We can now compare the lengths of two lists. So the expression

(length? list-1 list-2) returns true if the two lists are equal in length or one can add a comparison operator. For instance,

(length? list-1 list-2 <) returns true if the length of list-1 is less than the length of list-2. Here is the new code:

(define (string-or-list? x)(or (list? x)(string? x)))

(define-macro (length?)
  (let (len (length (args))
        fst (eval (args 0))
        scd (eval (args 1))
       )
  ;....if we have two lists to compare
  (if (and (<= 2 len 3)
           (string-or-list? fst)
           (string-or-list? scd))
      ((if (= len 2) = (eval (args 2)))
         (length fst)
         (length scd))
      ;....otherwise operate on a single list
      (apply length2? (map eval (args)))
  )
 )
)

(define (length2? lst (n 1)(op =) booltest)
  (and (op (length lst)
           (if (string-or-list? n)(length n) n))
       (if booltest
           (if (list? booltest)
               (for-all true?
                  (map for-all booltest (dup lst (length booltest))))
               (for-all booltest lst))
           true
       )))