                 (conj acc (nnth csv r)))
               [] (conj rs r))))
 
-;; TODO make this extensible
-;; Also don't test for equality of strings but that it contains the string...
-;; also make it work with regexes.
-(defn grep [csv f]
-  (if (instance? String f)
-    (grep csv #(= f %))
+(defmulti grep
+  "Filters rows in the table for matches.  This is multi-method
+  dispatches on the type of its second argument."
+  (fn [table f & cols] (class f)))
+
+(defmethod grep clojure.lang.IFn [csv f & cols]
+  (let [select-cols (if (empty? cols)
+                           identity
+                           (partial select-columns-from-row cols))]
     (filter (fn [row]
-              (some f row)) csv)))
+              (some f (select-cols row))) csv)))
 
-(defn remove-indices [col & idxs]
+(defmethod grep java.lang.String [csv s & cols]
+  (apply grep csv #(.contains % s) cols))
+
+(defmethod grep java.util.regex.Pattern [csv p & cols]
+  (apply grep csv #(re-find p %) cols))
+
+(defn- remove-indices [col & idxs]
   "Removes the values at the supplied indexes from the given vector."
   (let [pos (map - (sort idxs) (iterate inc 0))
         remove-index (fn [col pos]

  (rows earners (range 5 10))

  (-> (parse-csv "./examples/high-earners-pay-2012.csv")
      (grep "John")
      (fuse #(str %1 " " %2) 2 1)
      (columns 2 1)
      (rows 1 10))
  
  )

    (reduce remove-index col pos)))

(defn- fuse-row [columns f row]
  (let [to-drop (drop 1 (sort columns))
        merged (assoc row (apply min columns)
                      (apply f (select-columns-from-row columns row)))]
    (apply remove-indices merged to-drop)))

(defn fuse [csv f & cols]
  "Merge columns with the specified function"
  (map (partial fuse-row cols f) csv))

(defn join [])

