Path: utzoo!mnetor!uunet!seismo!sundc!pitstop!sun!decwrl!labrea!jade!ucbvax!sdcsvax!ucsdhub!hp-sdd!hplabs!otter!kers
From: kers@otter.HP.COM (Christopher Dollin)
Newsgroups: comp.lang.lisp
Subject: Filtering Vectors in CL Question
Message-ID: <1350001@otter.HP.COM>
Date: 17 Dec 87 10:59:17 GMT
Organization: hplabs-brc Bristol,UK.
Lines: 46

I have a query that has arisen out of local comparisons of Common Lisp and
Pop11.

What is the idiomatic and efficent way in CL to filter a vector; that is, to
make a new vector from an existing vector, containing only those elements
that satisfy some patameter predicate, and preserving the order?

The best I can think of is

    (defun filterv (v p)
        (let ( (vv (make-array (length v) :fill-pointer 0)) )
            (dotimes (i (length v))
                (if (funcall (p (aref v i)))
                    (vector-push vv (aref v i))
                )
            )
            vv
        )
    )

which seems to be rather ham-fisted, especially since it wastes space 
allocating an over-sized vector (if p actually removes any elements) and 
delivers an array with a fill-pointer, which may not be what you want (copying
to a simple vector may also not be what you want, as you've now wasted space
TWICE!).

What's the nice way? 

[Note: one Pop11 solution is

    define filter( v, p ); lvars v, procedure p;
        {% 
            appdata
                ( 
                v, 
                procedure ( x ); lvars x; if p( x ) then x endif endprocedure
                )
        %}
    enddefine;

which makes a vector out of all the elements in v that satisfy p, generates no
garbage, and runs acceptably fast].


Regards,
Kers                                    | "Why Lisp if you can talk Poperly?"