001  (ns sparse-array.extract
002    (:require [sparse-array.core :refer :all]))
003  
004  ;;; The whole point of working with sparse arrays is to work with interesting
005  ;;; subsets of arrays most of which are uninteresting. To extract an
006  ;;; interesting subset from an array, we're going to need an extract function.
007  
008  (defn- extract-from-sparse
009    "Return a subset of this sparse `array` comprising all those cells for which
010    this `function` returns a 'truthy' value."
011    [array function]
012    (reduce
013      merge
014      (apply
015        make-sparse-array
016        (cons
017          (:coord array)
018          (if (coll? (:content array)) (:content array))))
019      (map
020        #(if
021           (= :data (:content array))
022           (if (function (array %)) {% (array %)})
023           (let [v (extract-from-sparse (array %) function)]
024             (if
025               (empty?
026                 (filter integer? (keys v)))
027               nil
028               {% v})))
029        (filter integer? (keys array)))))
030  
031  (defn extract-from-dense
032    "Return a subset of this dense `array` comprising all those cells for which
033    this `function` returns a 'truthy' value. Use these `axes` if provided."
034    ([array function]
035     (extract-from-dense array function (map #(keyword (str "i" %)) (range))))
036    ([array function axes]
037     (let
038       [dimensions (dense-dimensions array)]
039       (reduce
040         merge
041         (apply make-sparse-array (take dimensions axes))
042         (if
043           (= dimensions 1)
044           (map
045             (fn [i v] (if (function v) (hash-map i v)))
046             (range)
047             array)
048           (map
049             (fn [i v] (if (empty? (filter integer? (keys v))) nil (hash-map i v)))
050             (range)
051             (map #(extract-from-dense % function (rest axes)) array)))))))
052  
053  (defn extract
054    "Return a sparse subset of this `array` - which may be either sparse or
055    dense - comprising all those cells for which this `function` returns a
056    'truthy' value."
057    [array function]
058    (cond
059      (sparse-array? array)
060      (extract-from-sparse array function)
061      (dense-array? array)
062      (extract-from-dense array function)
063      *safe-sparse-operations*
064      (throw
065        (ex-info
066          "Argument passed as `array` is neither sparse nor dense."
067          {:array array}))))
068