Arc Forumnew | comments | leaders | submitlogin
4 points by raymyers 6104 days ago | link | parent

I don't think there is a library call for this. The way to go would probably be:

    (def keep-rem (test seq) (list keep.test.seq rem.test.seq))
However, if you really wanted to do it in one pass, you might do this:

    (def keep-rem (test seq)
      (let f (testify test)
        (if (alist seq)
            ((afn (s)
               (if (no s) (list nil nil)
                   (let (tokeep torem) (self (cdr s))
                        (if (f (car s))
                            (list (cons (car s) tokeep) torem)
                            (list tokeep (cons (car s) torem))))))
             seq)
            (coerce (keep-rem test (coerce seq 'cons)) 'string))))
Then we could kick it up a notch with some pattern matching.

    (require "lib/defpat.arc")
    (def keep-rem (test seq)
      (let f (testify test)
        (if (alist seq)
            ((p-m:afn
              (())       (list nil nil)
              ((x . xs)) (let (tokeep torem) (self xs)
                              (if (f x)
                                  (list (cons x tokeep) torem)
                                  (list tokeep (cons x torem)))))
             seq)
            (coerce (keep-rem test (coerce seq 'cons)) 'string))))
Bam!


2 points by rkts 6104 days ago | link

This is a rare case where I think the tail-recursive solution is more readable:

  (def partition (f xs)
    (if (alist xs)
      (let f (testify f)
        ((afn (xs a b)
           (if (no xs)
             (list (rev a) (rev b))
             (f (car xs))
               (self (cdr xs) (cons (car xs) a) b)
               (self (cdr xs) a (cons (car xs) b))))
         xs nil nil))
      (map [coerce _ 'string] (partition f (coerce xs 'cons)))))
Also, how about generalizing accum to multiple lists?

  (mac accums (accfns . body)
    (let gaccs (map [uniq] accfns)
      `(withs ,(mappend (fn (gacc accfn)
                          (list gacc 'nil accfn `[push _ ,gacc]))
                        gaccs accfns)
         ,@body
         (list ,@(map [list 'rev _] gaccs)))))

  (def partition (f xs)
    (if (alist xs)
      (let f (testify f)
        (accums (a b) (each x xs ((if (f x) a b) x))))
      (map [coerce _ 'string] (partition f (coerce xs 'cons)))))

-----

3 points by almkglor 6104 days ago | link

True, although the final (rev a) (rev b) loses some of the speed benefit in the tail-recursion. If we didn't care about order (which happens quite often) we can drop the (rev ...) things. Otherwise, we can use a modulo-cons form, but this exceedingly complicated.

accums seems good... I suggest pushing it on nex-3's arc-wiki.

What I would like to see is a proper order-preserving accum. Here's a try at a "reasonably efficient" implementation:

  (mac accumf (accfn . body)
    " Collects or accumulates the values given to all calls to `accfn' within
      `body' and returns a list of those values.  The returned list
      is in the same order as calls to `accfn'.
      See also [[accum]] [[summing]] "
    (w/uniq (hd tl)
      `(let (,hd ,tl ,accfn) nil
            (= ,accfn
              (fn (s)
                (if ,hd
                    (do (= ,hd (cons s nil)) (= ,tl ,hd))
                    (do (= (cdr ,tl) (cons s nil)) (= ,tl (cdr ,tl))))))
            ,@body
            hd))))

-----

2 points by sacado 6104 days ago | link

Thanks for your answers ! I think that might be an interesting functionnality to add in the core functions. I used it a few times, in quite different contexts. Partitioning a list from a given criteria looks like a frequent action...

-----