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