Clojure

mapv, filterv

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: Release 1.4
  • Component/s: None
  • Labels:
    None
  • Patch:
    Code and Test
  • Approval:
    Ok

Description

Skip the intermediate sequence step when you know the result you want is a vector, i.e.

(defn mapv
  ([f coll]
     (-> (reduce (fn [v o] (conj! v (f o))) (transient []) coll)
         persistent!)))

(defn filterv
  [pred coll]
  (when-let [s (seq coll)]
    (-> (reduce (fn [v o] (if (pred o) (conj! v o) v))
                (transient [])
                coll)
        persistent!)))

Activity

Hide
Rich Hickey added a comment -

There's no perf benefit for other arities of map, so for those just define in terms of (into [] (map ...))

Why when-let in filterv? Not returning a vector then. You don't even use s.

Show
Rich Hickey added a comment - There's no perf benefit for other arities of map, so for those just define in terms of (into [] (map ...)) Why when-let in filterv? Not returning a vector then. You don't even use s.
Hide
Alan Dipert added a comment - - edited

What was the problem with defining mapv and filterv in terms of reducev? This is what I had in mind:

(defn reducev
  [f coll]
  (persistent! (reduce f (transient []) coll)))

(defn mapv
  ([f coll]
     (reducev #(conj! % (f %2)) coll))
  ([f coll & colls]
     (into [] (apply map f coll colls))))

(defn filterv
  [pred coll]
  (reducev #(if (pred %2) (conj! % %2) %) coll))
Show
Alan Dipert added a comment - - edited What was the problem with defining mapv and filterv in terms of reducev? This is what I had in mind:
(defn reducev
  [f coll]
  (persistent! (reduce f (transient []) coll)))

(defn mapv
  ([f coll]
     (reducev #(conj! % (f %2)) coll))
  ([f coll & colls]
     (into [] (apply map f coll colls))))

(defn filterv
  [pred coll]
  (reducev #(if (pred %2) (conj! % %2) %) coll))
Hide
Stuart Halloway added a comment -

Alan: My original thought was that map and filter are boths fns from collection to collection. reduce is not, so making a reducev that pretends reduce is like map and filter is a little confusing.

But looking at the code I like it.

Rich: ok on both points, thanks.

Show
Stuart Halloway added a comment - Alan: My original thought was that map and filter are boths fns from collection to collection. reduce is not, so making a reducev that pretends reduce is like map and filter is a little confusing. But looking at the code I like it. Rich: ok on both points, thanks.
Hide
Rich Hickey added a comment -

The problem is - what are the semantics of reducev? Is this for the public or an implementation detail? mapv and filterv take the same f and pred as map and filter, but reducev doesn't take the same f as reduce, it requires a very special, implementation-dependent f.

Show
Rich Hickey added a comment - The problem is - what are the semantics of reducev? Is this for the public or an implementation detail? mapv and filterv take the same f and pred as map and filter, but reducev doesn't take the same f as reduce, it requires a very special, implementation-dependent f.
Hide
Kevin Downey added a comment -

why not implement in terms of reduce (inline reducev)?

Show
Kevin Downey added a comment - why not implement in terms of reduce (inline reducev)?
Hide
Stuart Halloway added a comment -

I see no benefit in separate reducev

Show
Stuart Halloway added a comment - I see no benefit in separate reducev
Hide
Rich Hickey added a comment -

someone other than Stu should screen this

Show
Rich Hickey added a comment - someone other than Stu should screen this
Hide
Stuart Sierra added a comment -

Microbenchmark shows performance improvement:

user=> (dotimes [i 5] (time (dotimes [j 10000] (vec (map inc (range 100))))))
"Elapsed time: 119.799 msecs"
"Elapsed time: 80.959 msecs"
"Elapsed time: 75.242 msecs"
"Elapsed time: 75.622 msecs"
"Elapsed time: 73.646 msecs"
nil
user=> (dotimes [i 5] (time (dotimes [j 10000] (mapv inc (range 100)))))
"Elapsed time: 199.096 msecs"
"Elapsed time: 61.737 msecs"
"Elapsed time: 49.911 msecs"
"Elapsed time: 50.421 msecs"
"Elapsed time: 48.437 msecs"
nil
Show
Stuart Sierra added a comment - Microbenchmark shows performance improvement:
user=> (dotimes [i 5] (time (dotimes [j 10000] (vec (map inc (range 100))))))
"Elapsed time: 119.799 msecs"
"Elapsed time: 80.959 msecs"
"Elapsed time: 75.242 msecs"
"Elapsed time: 75.622 msecs"
"Elapsed time: 73.646 msecs"
nil
user=> (dotimes [i 5] (time (dotimes [j 10000] (mapv inc (range 100)))))
"Elapsed time: 199.096 msecs"
"Elapsed time: 61.737 msecs"
"Elapsed time: 49.911 msecs"
"Elapsed time: 50.421 msecs"
"Elapsed time: 48.437 msecs"
nil
Hide
Stuart Sierra added a comment -

Screened by the other Stuart.

Show
Stuart Sierra added a comment - Screened by the other Stuart.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: